GP-1447: Added 'View all Memory' override toggle to Debugger.

This commit is contained in:
Dan 2021-11-23 10:49:00 -05:00
parent 59402a2951
commit 8b2af5241a
30 changed files with 674 additions and 229 deletions

View file

@ -65,5 +65,14 @@
<P>This action is available when the dynamic listing's cursor is at a valid location. It
selects the region containing that cursor. If the dynamic listing has a selection, it selects
all regions intersecting that selection.</P>
<H3><A name="force_full_view"></A>Force Full View</H3>
<P>This action is available when a trace is active. It forces all physical address spaces into
the view. Ordinarily, only those addresses contained in a region at the active snap are
presented in the listing and memory windows. When this toggle is on, regions are ignored.
Instead, all physical addresses are presented. (Here "physical" includes all memory spaces
except <CODE>OTHER</CODE>.) This toggle applies only to the current trace for the duration it
is open.</P>
</BODY>
</HTML>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before After
Before After

View file

@ -1749,6 +1749,22 @@ public interface DebuggerResources {
}
}
interface ForceFullViewAction {
String NAME = "Force Full View";
String DESCRIPTION = "Ignore regions and fiew full address spaces";
String GROUP = GROUP_GENERAL;
String HELP_ANCHOR = "force_full_view";
static ToggleActionBuilder builder(Plugin owner) {
String ownerName = owner.getName();
return new ToggleActionBuilder(NAME, ownerName)
.description(DESCRIPTION)
.menuGroup(GROUP_GENERAL)
.menuPath(NAME)
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
}
}
public abstract class AbstractDebuggerConnectionsNode extends GTreeNode {
@Override
public String getName() {

View file

@ -46,8 +46,14 @@ public class DebuggerMemoryByteViewerComponent extends ByteViewerComponent
List<ColoredFieldSelection> selections) {
Color selectionColor = paintContext.getSelectionColor();
Color highlightColor = paintContext.getHighlightColor();
selections.add(new ColoredFieldSelection(getSelection(), selectionColor));
selections.add(new ColoredFieldSelection(getHighlight(), highlightColor));
FieldSelection selection = getSelection();
if (!selection.isEmpty()) {
selections.add(new ColoredFieldSelection(selection, selectionColor));
}
FieldSelection highlight = getHighlight();
if (!highlight.isEmpty()) {
selections.add(new ColoredFieldSelection(highlight, highlightColor));
}
}
}

View file

@ -35,8 +35,7 @@ import docking.widgets.table.CustomToStringCellRenderer;
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractSelectAddressesAction;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.SelectRowsAction;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
import ghidra.app.plugin.core.debug.utils.DebouncedRowWrappedEnumeratedColumnTableModel;
import ghidra.app.services.DebuggerListingService;
import ghidra.app.services.DebuggerTraceManagerService;
@ -233,6 +232,7 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
SelectAddressesAction actionSelectAddresses;
DockingAction actionSelectRows;
ToggleDockingAction actionForceFullView;
public DebuggerRegionsProvider(DebuggerRegionsPlugin plugin) {
super(plugin.getTool(), DebuggerResources.TITLE_PROVIDER_REGIONS, plugin.getName(),
@ -341,6 +341,11 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
.enabledWhen(ctx -> currentTrace != null)
.onAction(this::activatedSelectCurrent)
.buildAndInstallLocal(this);
actionForceFullView = ForceFullViewAction.builder(plugin)
.enabledWhen(ctx -> currentTrace != null)
.onAction(this::activatedForceFullView)
.buildAndInstallLocal(this);
}
private void activatedSelectCurrent(ActionContext ignored) {
@ -371,6 +376,15 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
}
}
private void activatedForceFullView(ActionContext ignored) {
if (currentTrace == null) {
return;
}
currentTrace.getProgramView()
.getMemory()
.setForceFullView(actionForceFullView.isSelected());
}
public void setSelectedRegions(Set<TraceMemoryRegion> sel) {
DebuggerResources.setSelectedRows(sel, regionTableModel::getRow, regionTable,
regionTableModel, regionFilterPanel);
@ -396,6 +410,16 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
contextChanged();
}
@Override
public void contextChanged() {
super.contextChanged();
if (currentTrace != null) {
actionForceFullView.setSelected(currentTrace.getProgramView()
.getMemory()
.isForceFullView());
}
}
private void removeOldListeners() {
if (currentTrace == null) {
return;

View file

@ -716,30 +716,38 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
}
}
public void updateViewsAddBlock(DBTraceMemoryRegion region) {
allViews(v -> v.updateMemoryAddBlock(region));
public void updateViewsAddRegionBlock(DBTraceMemoryRegion region) {
allViews(v -> v.updateMemoryAddRegionBlock(region));
}
public void updateViewsChangeBlockName(DBTraceMemoryRegion region) {
allViews(v -> v.updateMemoryChangeBlockName(region));
public void updateViewsChangeRegionBlockName(DBTraceMemoryRegion region) {
allViews(v -> v.updateMemoryChangeRegionBlockName(region));
}
public void updateViewsChangeBlockFlags(DBTraceMemoryRegion region) {
allViews(v -> v.updateMemoryChangeBlockFlags(region));
public void updateViewsChangeRegionBlockFlags(DBTraceMemoryRegion region) {
allViews(v -> v.updateMemoryChangeRegionBlockFlags(region));
}
public void updateViewsChangeBlockRange(DBTraceMemoryRegion region,
public void updateViewsChangeRegionBlockRange(DBTraceMemoryRegion region,
AddressRange oldRange, AddressRange newRange) {
allViews(v -> v.updateMemoryChangeBlockRange(region, oldRange, newRange));
allViews(v -> v.updateMemoryChangeRegionBlockRange(region, oldRange, newRange));
}
public void updateViewsChangeBlockLifespan(DBTraceMemoryRegion region,
public void updateViewsChangeRegionBlockLifespan(DBTraceMemoryRegion region,
Range<Long> oldLifespan, Range<Long> newLifespan) {
allViews(v -> v.updateMemoryChangeBlockLifespan(region, oldLifespan, newLifespan));
allViews(v -> v.updateMemoryChangeRegionBlockLifespan(region, oldLifespan, newLifespan));
}
public void updateViewsDeleteBlock(DBTraceMemoryRegion region) {
allViews(v -> v.updateMemoryDeleteBlock(region));
public void updateViewsDeleteRegionBlock(DBTraceMemoryRegion region) {
allViews(v -> v.updateMemoryDeleteRegionBlock(region));
}
public void updateViewsAddSpaceBlock(AddressSpace space) {
allViews(v -> v.updateMemoryAddSpaceBlock(space));
}
public void updateViewsDeleteSpaceBlock(AddressSpace space) {
allViews(v -> v.updateMemoryDeleteSpaceBlock(space));
}
public void updateViewsRefreshBlocks() {

View file

@ -255,6 +255,7 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
// Only if it succeeds do we store the record
DBTraceOverlaySpaceEntry ent = overlayStore.create();
ent.set(space.getName(), base.getName());
trace.updateViewsAddSpaceBlock(space);
return space;
}
}
@ -268,7 +269,10 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
}
overlayStore.delete(exists);
TraceAddressFactory factory = trace.getInternalAddressFactory();
AddressSpace space = factory.getAddressSpace(name);
assert space != null;
factory.removeOverlaySpace(name);
trace.updateViewsDeleteSpaceBlock(space);
}
}
}

View file

@ -154,7 +154,7 @@ public class DBTraceMemoryRegion
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
this.name = name;
update(NAME_COLUMN);
space.trace.updateViewsChangeBlockName(this);
space.trace.updateViewsChangeRegionBlockName(this);
}
space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
@ -175,7 +175,7 @@ public class DBTraceMemoryRegion
checkPathConflicts(newLifespan, path);
Range<Long> oldLifespan = getLifespan();
doSetLifespan(newLifespan);
space.trace.updateViewsChangeBlockLifespan(this, oldLifespan, newLifespan);
space.trace.updateViewsChangeRegionBlockLifespan(this, oldLifespan, newLifespan);
space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.LIFESPAN_CHANGED,
space, this, oldLifespan, newLifespan));
@ -218,7 +218,7 @@ public class DBTraceMemoryRegion
oldRange = range;
checkOverlapConflicts(lifespan, newRange);
doSetRange(newRange);
space.trace.updateViewsChangeBlockRange(this, oldRange, newRange);
space.trace.updateViewsChangeRegionBlockRange(this, oldRange, newRange);
}
space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
@ -278,7 +278,7 @@ public class DBTraceMemoryRegion
this.flags.add(f);
}
update(FLAGS_COLUMN);
space.trace.updateViewsChangeBlockFlags(this);
space.trace.updateViewsChangeRegionBlockFlags(this);
}
space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
@ -293,7 +293,7 @@ public class DBTraceMemoryRegion
this.flags.add(f);
}
update(FLAGS_COLUMN);
space.trace.updateViewsChangeBlockFlags(this);
space.trace.updateViewsChangeRegionBlockFlags(this);
}
space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
@ -308,7 +308,7 @@ public class DBTraceMemoryRegion
this.flags.remove(f);
}
update(FLAGS_COLUMN);
space.trace.updateViewsChangeBlockFlags(this);
space.trace.updateViewsChangeRegionBlockFlags(this);
}
space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));

View file

@ -161,7 +161,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
DBTraceMemoryRegion region =
regionMapSpace.put(new ImmutableTraceAddressSnapRange(range, lifespan), null);
region.set(path, path, flags);
trace.updateViewsAddBlock(region);
trace.updateViewsAddRegionBlock(region);
trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.ADDED, this, region));
return region;
@ -244,7 +244,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
try (LockHold hold = LockHold.lock(lock.writeLock())) {
regionMapSpace.deleteData(region);
regionCache.remove(region);
trace.updateViewsDeleteBlock(region);
trace.updateViewsDeleteRegionBlock(region);
trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.DELETED, this, region));
}

View file

@ -69,6 +69,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
DBTraceMemorySpace mem = trace.getMemoryManager().get(this, false);
if (mem == null) {
// TODO: 0-fill instead? Will need to check memory space bounds.
return 0;
}
return mem.getViewBytes(program.snap, address.add(addressOffset), buffer);
}

View file

@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.function.Consumer;
import com.google.common.cache.RemovalNotification;
@ -42,6 +43,7 @@ public abstract class AbstractDBTraceProgramViewMemory
protected final DBTraceMemoryManager memoryManager;
protected AddressSetView addressSet;
protected boolean forceFullView = false;
protected long snap;
public AbstractDBTraceProgramViewMemory(DBTraceProgramView program) {
@ -50,16 +52,57 @@ public abstract class AbstractDBTraceProgramViewMemory
setSnap(program.snap);
}
protected void blockRemoved(
RemovalNotification<DBTraceMemoryRegion, DBTraceProgramViewMemoryBlock> rn) {
protected void regionBlockRemoved(
RemovalNotification<DBTraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> rn) {
// Nothing
}
protected void spaceBlockRemoved(
RemovalNotification<AddressSpace, DBTraceProgramViewMemorySpaceBlock> rn) {
// Nothing
}
protected abstract void recomputeAddressSet();
protected void forPhysicalSpaces(Consumer<AddressSpace> consumer) {
for (AddressSpace space : program.getAddressFactory().getAddressSpaces()) {
// NB. Overlay's isMemory depends on its base space
// TODO: Allow other?
// For some reason "other" is omitted from factory.getAddressSet
if (space.isMemorySpace() && space.getType() != AddressSpace.TYPE_OTHER) {
consumer.accept(space);
}
}
}
protected void computeFullAdddressSet() {
AddressSet temp = new AddressSet();
forPhysicalSpaces(space -> temp.add(space.getMinAddress(), space.getMaxAddress()));
addressSet = temp;
}
@Override
public void setForceFullView(boolean forceFullView) {
this.forceFullView = forceFullView;
if (forceFullView) {
computeFullAdddressSet();
}
else {
recomputeAddressSet();
}
program.fireObjectRestored();
}
@Override
public boolean isForceFullView() {
return forceFullView;
}
void setSnap(long snap) {
this.snap = snap;
recomputeAddressSet();
if (!forceFullView) {
recomputeAddressSet();
}
}
@Override
@ -463,17 +506,23 @@ public abstract class AbstractDBTraceProgramViewMemory
}
protected synchronized void addRange(AddressRange range) {
addressSet = addressSet.union(new AddressSet(range));
if (!forceFullView) {
addressSet = addressSet.union(new AddressSet(range));
}
}
protected synchronized void removeRange(AddressRange range) {
addressSet = addressSet.subtract(new AddressSet(range));
if (!forceFullView) {
addressSet = addressSet.subtract(new AddressSet(range));
}
}
protected synchronized void changeRange(AddressRange remove, AddressRange add) {
AddressSet temp = new AddressSet(addressSet);
temp.delete(remove);
temp.add(add);
addressSet = temp;
if (!forceFullView) {
AddressSet temp = new AddressSet(addressSet);
temp.delete(remove);
temp.add(add);
addressSet = temp;
}
}
}

View file

@ -16,42 +16,39 @@
package ghidra.trace.database.program;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.*;
import ghidra.framework.store.LockException;
import ghidra.program.database.mem.ByteMappingScheme;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.*;
import ghidra.trace.database.memory.DBTraceMemoryRegion;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.memory.TraceMemorySpaceInputStream;
import ghidra.util.MathUtilities;
// TODO: Proper locking all over here
public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
public abstract class AbstractDBTraceProgramViewMemoryBlock implements MemoryBlock {
private class DBTraceProgramViewMemoryBlockSourceInfo implements MemoryBlockSourceInfo {
private class MyMemoryBlockSourceInfo implements MemoryBlockSourceInfo {
@Override
public long getLength() {
return region.getLength();
return getMemoryBlock().getSize();
}
@Override
public Address getMinAddress() {
return region.getMinAddress();
return getMemoryBlock().getStart();
}
@Override
public Address getMaxAddress() {
return region.getMaxAddress();
return getMemoryBlock().getEnd();
}
@Override
public String getDescription() {
return "Trace region: " + region;
return getInfoDescription();
}
@Override
@ -81,12 +78,12 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
@Override
public MemoryBlock getMemoryBlock() {
return DBTraceProgramViewMemoryBlock.this;
return AbstractDBTraceProgramViewMemoryBlock.this;
}
@Override
public boolean contains(Address address) {
return region.getRange().contains(address);
return getMemoryBlock().contains(address);
}
@Override
@ -95,15 +92,26 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
}
}
private final DBTraceProgramView program;
private final DBTraceMemoryRegion region;
protected final DBTraceProgramView program;
private final List<MemoryBlockSourceInfo> info =
Collections.singletonList(new DBTraceProgramViewMemoryBlockSourceInfo());
Collections.singletonList(new MyMemoryBlockSourceInfo());
public DBTraceProgramViewMemoryBlock(DBTraceProgramView program, DBTraceMemoryRegion region) {
protected AbstractDBTraceProgramViewMemoryBlock(DBTraceProgramView program) {
this.program = program;
this.region = region;
}
protected abstract String getInfoDescription();
protected AddressSpace getAddressSpace() {
return getStart().getAddressSpace();
}
protected DBTraceMemorySpace getMemorySpace() {
return program.trace.getMemoryManager().getMemorySpace(getAddressSpace(), false);
}
protected AddressRange getAddressRange() {
return new AddressRangeImpl(getStart(), getEnd());
}
@Override
@ -111,112 +119,40 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
return this.getStart().compareTo(that.getStart());
}
@Override
public void setPermissions(boolean read, boolean write, boolean execute) {
region.setRead(read);
region.setWrite(write);
region.setExecute(execute);
}
@Override
public int getPermissions() {
int bits = 0;
for (TraceMemoryFlag flag : region.getFlags()) {
bits |= flag.getBits();
}
return bits;
}
@Override
public InputStream getData() {
AddressRange range = region.getRange();
DBTraceMemorySpace space =
program.trace.getMemoryManager().getMemorySpace(range.getAddressSpace(), false);
if (space == null) {
return null;
}
return new TraceMemorySpaceInputStream(program, space, range);
}
@Override
public boolean contains(Address addr) {
return region.getRange().contains(addr);
}
@Override
public Address getStart() {
return region.getRange().getMinAddress();
}
@Override
public Address getEnd() {
return region.getRange().getMaxAddress();
return getAddressRange().contains(addr);
}
@Override
public long getSize() {
return region.getRange().getLength();
return getEnd().subtract(getStart()) + 1;
}
@Override
public String getName() {
return region.getName();
}
@Override
public void setName(String name) throws LockException {
region.setName(name);
public BigInteger getSizeAsBigInteger() {
return getEnd().getOffsetAsBigInteger()
.subtract(getStart().getOffsetAsBigInteger())
.add(BigInteger.ONE);
}
@Override
public String getComment() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setComment(String comment) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
}
@Override
public boolean isRead() {
return region.isRead();
}
@Override
public void setRead(boolean r) {
region.setRead(r);
}
@Override
public boolean isWrite() {
return region.isWrite();
}
@Override
public void setWrite(boolean w) {
region.setWrite(w);
}
@Override
public boolean isExecute() {
return region.isExecute();
}
@Override
public void setExecute(boolean e) {
region.setExecute(e);
}
@Override
public boolean isVolatile() {
return region.isVolatile();
}
@Override
public void setVolatile(boolean v) {
region.setVolatile(v);
public InputStream getData() {
DBTraceMemorySpace ms = getMemorySpace();
if (ms == null) {
return null;
}
return new TraceMemorySpaceInputStream(program, ms, getAddressRange());
}
@Override
@ -231,7 +167,7 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
@Override
public byte getByte(Address addr) throws MemoryAccessException {
AddressRange range = region.getRange();
AddressRange range = getAddressRange();
if (!range.contains(addr)) {
throw new MemoryAccessException();
}
@ -254,7 +190,7 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
@Override
public int getBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException {
AddressRange range = region.getRange();
AddressRange range = getAddressRange();
if (!range.contains(addr)) {
throw new MemoryAccessException();
}
@ -263,7 +199,7 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
if (space == null) {
throw new MemoryAccessException("Space does not exist");
}
len = (int) Math.min(len, range.getMaxAddress().subtract(addr) + 1);
len = MathUtilities.unsignedMin(len, range.getMaxAddress().subtract(addr) + 1);
return space.getViewBytes(program.snap, addr, ByteBuffer.wrap(b, off, len));
}
@ -281,7 +217,7 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
@Override
public int putBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException {
AddressRange range = region.getRange();
AddressRange range = getAddressRange();
if (!range.contains(addr)) {
throw new MemoryAccessException();
}
@ -308,7 +244,8 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
@Override
public boolean isOverlay() {
return false;
// TODO: What effect does this have? Does it makes sense for trace "overlays"?
return getAddressSpace().isOverlaySpace();
}
@Override

View file

@ -943,6 +943,13 @@ public class DBTraceProgramView implements TraceProgramView {
}
}
/**
* Fires object-restored event on this view and all associated register views.
*/
protected void fireObjectRestored() {
fireEventAllViews(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_RESTORED));
}
@Override
public String toString() {
return String.format("<%s on %s at snap=%d>", getClass().getSimpleName(), trace, snap);
@ -1555,52 +1562,63 @@ public class DBTraceProgramView implements TraceProgramView {
trace.removeTransactionListener(listener);
}
public void updateMemoryAddBlock(DBTraceMemoryRegion region) {
public void updateMemoryAddRegionBlock(DBTraceMemoryRegion region) {
if (!isRegionVisible(region)) {
return;
}
memory.updateAddBlock(region);
memory.updateAddRegionBlock(region);
}
public void updateMemoryChangeBlockName(DBTraceMemoryRegion region) {
public void updateMemoryChangeRegionBlockName(DBTraceMemoryRegion region) {
if (!isRegionVisible(region)) {
return;
}
memory.updateChangeBlockName(region);
memory.updateChangeRegionBlockName(region);
}
public void updateMemoryChangeBlockFlags(DBTraceMemoryRegion region) {
public void updateMemoryChangeRegionBlockFlags(DBTraceMemoryRegion region) {
if (!isRegionVisible(region)) {
return;
}
memory.updateChangeBlockFlags(region);
memory.updateChangeRegionBlockFlags(region);
}
public void updateMemoryChangeBlockRange(DBTraceMemoryRegion region, AddressRange oldRange,
public void updateMemoryChangeRegionBlockRange(DBTraceMemoryRegion region,
AddressRange oldRange,
AddressRange newRange) {
if (!isRegionVisible(region)) {
return;
}
memory.updateChangeBlockRange(region, oldRange, newRange);
memory.updateChangeRegionBlockRange(region, oldRange, newRange);
}
public void updateMemoryChangeBlockLifespan(DBTraceMemoryRegion region,
public void updateMemoryChangeRegionBlockLifespan(DBTraceMemoryRegion region,
Range<Long> oldLifespan, Range<Long> newLifespan) {
boolean inOld = isRegionVisible(region, oldLifespan);
boolean inNew = isRegionVisible(region, newLifespan);
if (inOld && !inNew) {
memory.updateDeleteBlock(region);
memory.updateDeleteRegionBlock(region);
}
if (!inOld && inNew) {
memory.updateAddBlock(region);
memory.updateAddRegionBlock(region);
}
}
public void updateMemoryDeleteBlock(DBTraceMemoryRegion region) {
public void updateMemoryDeleteRegionBlock(DBTraceMemoryRegion region) {
if (!isRegionVisible(region)) {
return;
}
memory.updateAddBlock(region);
memory.updateAddRegionBlock(region);
}
public void updateMemoryAddSpaceBlock(AddressSpace space) {
// Spaces not not time-bound. No visibility check.
memory.updateAddSpaceBlock(space);
}
public void updateMemoryDeleteSpaceBlock(AddressSpace space) {
// Spaces not not time-bound. No visibility check.
memory.updateDeleteSpaceBlock(space);
}
public void updateMemoryRefreshBlocks() {

View file

@ -27,8 +27,19 @@ import ghidra.trace.database.memory.DBTraceMemoryRegion;
public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
private final Map<DBTraceMemoryRegion, DBTraceProgramViewMemoryBlock> blocks =
CacheBuilder.newBuilder().removalListener(this::blockRemoved).weakValues().build().asMap();
// NB. Keep both per-region and force-full (per-space) block sets ready
private final Map<DBTraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> regionBlocks =
CacheBuilder.newBuilder()
.removalListener(this::regionBlockRemoved)
.weakValues()
.build()
.asMap();
private final Map<AddressSpace, DBTraceProgramViewMemorySpaceBlock> spaceBlocks =
CacheBuilder.newBuilder()
.removalListener(this::spaceBlockRemoved)
.weakValues()
.build()
.asMap();
public DBTraceProgramViewMemory(DBTraceProgramView program) {
super(program);
@ -64,58 +75,84 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
addressSet = temp;
}
protected MemoryBlock getBlock(DBTraceMemoryRegion region) {
return blocks.computeIfAbsent(region,
r -> new DBTraceProgramViewMemoryBlock(program, region));
protected MemoryBlock getRegionBlock(DBTraceMemoryRegion region) {
return regionBlocks.computeIfAbsent(region,
r -> new DBTraceProgramViewMemoryRegionBlock(program, region));
}
protected MemoryBlock getSpaceBlock(AddressSpace space) {
return spaceBlocks.computeIfAbsent(space,
s -> new DBTraceProgramViewMemorySpaceBlock(program, space));
}
@Override
public MemoryBlock getBlock(Address addr) {
if (forceFullView) {
return getSpaceBlock(addr.getAddressSpace());
}
DBTraceMemoryRegion region = getTopRegion(s -> memoryManager.getRegionContaining(s, addr));
return region == null ? null : getBlock(region);
return region == null ? null : getRegionBlock(region);
}
@Override
public MemoryBlock getBlock(String blockName) {
if (forceFullView) {
AddressSpace space = program.getAddressFactory().getAddressSpace(blockName);
return space == null ? null : getSpaceBlock(space);
}
DBTraceMemoryRegion region =
getTopRegion(s -> memoryManager.getLiveRegionByPath(s, blockName));
return region == null ? null : getBlock(region);
return region == null ? null : getRegionBlock(region);
}
@Override
public MemoryBlock[] getBlocks() {
List<MemoryBlock> result = new ArrayList<>();
forVisibleRegions(reg -> result.add(getBlock(reg)));
if (forceFullView) {
forPhysicalSpaces(space -> result.add(getSpaceBlock(space)));
}
else {
forVisibleRegions(reg -> result.add(getRegionBlock(reg)));
}
Collections.sort(result, Comparator.comparing(b -> b.getStart()));
return result.toArray(new MemoryBlock[result.size()]);
}
public void updateAddBlock(DBTraceMemoryRegion region) {
public void updateAddRegionBlock(DBTraceMemoryRegion region) {
// TODO: add block to cache?
addRange(region.getRange());
}
public void updateChangeBlockName(DBTraceMemoryRegion region) {
public void updateChangeRegionBlockName(DBTraceMemoryRegion region) {
// Nothing. Block name is taken from region, uncached
}
public void updateChangeBlockFlags(DBTraceMemoryRegion region) {
public void updateChangeRegionBlockFlags(DBTraceMemoryRegion region) {
// Nothing. Block flags are taken from region, uncached
}
public void updateChangeBlockRange(DBTraceMemoryRegion region, AddressRange oldRange,
public void updateChangeRegionBlockRange(DBTraceMemoryRegion region, AddressRange oldRange,
AddressRange newRange) {
// TODO: update cached block? Nothing to update.
changeRange(oldRange, newRange);
}
public void updateDeleteBlock(DBTraceMemoryRegion region) {
blocks.remove(region);
public void updateDeleteRegionBlock(DBTraceMemoryRegion region) {
regionBlocks.remove(region);
removeRange(region.getRange());
}
public void updateAddSpaceBlock(AddressSpace space) {
// Nothing. Cache will construct it upon request, lazily
}
public void updateDeleteSpaceBlock(AddressSpace space) {
spaceBlocks.remove(space);
}
public void updateRefreshBlocks() {
blocks.clear();
regionBlocks.clear();
spaceBlocks.clear();
recomputeAddressSet();
}
}

View file

@ -0,0 +1,150 @@
/* ###
* 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.trace.database.program;
import java.io.InputStream;
import java.math.BigInteger;
import ghidra.framework.store.LockException;
import ghidra.program.model.address.*;
import ghidra.trace.database.memory.DBTraceMemoryRegion;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.memory.TraceMemorySpaceInputStream;
// TODO: Proper locking all over here
public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramViewMemoryBlock {
private final DBTraceMemoryRegion region;
public DBTraceProgramViewMemoryRegionBlock(DBTraceProgramView program,
DBTraceMemoryRegion region) {
super(program);
this.region = region;
}
@Override
protected String getInfoDescription() {
return "Trace region: " + region;
}
@Override
protected AddressSpace getAddressSpace() {
return region.getRange().getAddressSpace();
}
@Override
protected AddressRange getAddressRange() {
return region.getRange();
}
@Override
public void setPermissions(boolean read, boolean write, boolean execute) {
region.setRead(read);
region.setWrite(write);
region.setExecute(execute);
}
@Override
public int getPermissions() {
int bits = 0;
for (TraceMemoryFlag flag : region.getFlags()) {
bits |= flag.getBits();
}
return bits;
}
@Override
public InputStream getData() {
AddressRange range = region.getRange();
DBTraceMemorySpace space =
program.trace.getMemoryManager().getMemorySpace(range.getAddressSpace(), false);
if (space == null) {
return null;
}
return new TraceMemorySpaceInputStream(program, space, range);
}
@Override
public Address getStart() {
return region.getRange().getMinAddress();
}
@Override
public Address getEnd() {
return region.getRange().getMaxAddress();
}
@Override
public long getSize() {
return region.getRange().getLength();
}
@Override
public BigInteger getSizeAsBigInteger() {
return region.getRange().getBigLength();
}
@Override
public String getName() {
return region.getName();
}
@Override
public void setName(String name) throws LockException {
region.setName(name);
}
@Override
public boolean isRead() {
return region.isRead();
}
@Override
public void setRead(boolean r) {
region.setRead(r);
}
@Override
public boolean isWrite() {
return region.isWrite();
}
@Override
public void setWrite(boolean w) {
region.setWrite(w);
}
@Override
public boolean isExecute() {
return region.isExecute();
}
@Override
public void setExecute(boolean e) {
region.setExecute(e);
}
@Override
public boolean isVolatile() {
return region.isVolatile();
}
@Override
public void setVolatile(boolean v) {
region.setVolatile(v);
}
}

View file

@ -0,0 +1,137 @@
/* ###
* 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.trace.database.program;
import java.io.InputStream;
import java.util.*;
import ghidra.framework.store.LockException;
import ghidra.program.database.mem.ByteMappingScheme;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.*;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.model.memory.TraceMemorySpaceInputStream;
public class DBTraceProgramViewMemorySpaceBlock extends AbstractDBTraceProgramViewMemoryBlock {
private final AddressSpace space;
public DBTraceProgramViewMemorySpaceBlock(DBTraceProgramView program, AddressSpace space) {
super(program);
this.space = space;
}
@Override
protected String getInfoDescription() {
return "Trace space: " + space;
}
@Override
protected AddressSpace getAddressSpace() {
return space;
}
@Override
public Address getStart() {
return space.getMinAddress();
}
@Override
public Address getEnd() {
return space.getMaxAddress();
}
@Override
public int getPermissions() {
return MemoryBlock.READ | MemoryBlock.WRITE | MemoryBlock.EXECUTE;
}
@Override
public String getName() {
return space.getName();
}
@Override
public void setName(String name) throws IllegalArgumentException, LockException {
throw new UnsupportedOperationException();
}
@Override
public String getComment() {
return null;
}
@Override
public void setComment(String comment) {
throw new UnsupportedOperationException();
}
@Override
public boolean isRead() {
return true;
}
@Override
public void setRead(boolean r) {
throw new UnsupportedOperationException();
}
@Override
public boolean isWrite() {
return true;
}
@Override
public void setWrite(boolean w) {
throw new UnsupportedOperationException();
}
@Override
public boolean isExecute() {
return true;
}
@Override
public void setExecute(boolean e) {
throw new UnsupportedOperationException();
}
@Override
public void setPermissions(boolean read, boolean write, boolean execute) {
throw new UnsupportedOperationException();
}
@Override
public boolean isVolatile() {
return false;
}
@Override
public void setVolatile(boolean v) {
throw new UnsupportedOperationException();
}
@Override
public String getSourceName() {
return "Trace"; // TODO: What does this method actually do?
}
@Override
public void setSourceName(String sourceName) {
throw new UnsupportedOperationException();
}
}

View file

@ -33,6 +33,11 @@ public class DBTraceProgramViewRegisterMemory extends AbstractDBTraceProgramView
space.getAddressSpace().getMaxAddress()));
}
@Override
public void setForceFullView(boolean forceFullView) {
throw new UnsupportedOperationException();
}
@Override
protected void recomputeAddressSet() {
// AddressSet is always full space

View file

@ -16,6 +16,7 @@
package ghidra.trace.database.program;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.*;
@ -144,6 +145,11 @@ public class DBTraceProgramViewRegisterMemoryBlock implements MemoryBlock {
return range.getLength();
}
@Override
public BigInteger getSizeAsBigInteger() {
return range.getBigLength();
}
@Override
public String getName() {
return REGS_BLOCK_NAME;

View file

@ -28,7 +28,6 @@ import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.reloc.RelocationTable;
import ghidra.program.model.symbol.*;
@ -40,6 +39,7 @@ import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.Trace;
import ghidra.trace.model.data.TraceBasedDataTypeManager;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.program.TraceProgramViewMemory;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceTimeViewport;
import ghidra.util.exception.CancelledException;
@ -113,7 +113,7 @@ public class DBTraceProgramViewRegisters implements TraceProgramView {
}
@Override
public Memory getMemory() {
public TraceProgramViewMemory getMemory() {
return memory;
}

View file

@ -37,13 +37,6 @@ public class DBTraceVariableSnapProgramView extends DBTraceProgramView
super(trace, snap, compilerSpec);
}
/**
* Fires object-restored event on this view and all associated register views.
*/
protected void fireObjectRestored() {
fireEventAllViews(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_RESTORED));
}
@Override
public void setSnap(long newSnap) {
if (this.snap == newSnap) {

View file

@ -24,6 +24,10 @@ import ghidra.trace.util.TraceTimeViewport;
* View of a trace at a particular time, as a program
*/
public interface TraceProgramView extends Program {
@Override
TraceProgramViewMemory getMemory();
/**
* Get the trace this view presents
*

View file

@ -20,4 +20,8 @@ import ghidra.program.model.mem.Memory;
public interface TraceProgramViewMemory extends Memory, SnapSpecificTraceView {
@Override
TraceProgramView getProgram();
void setForceFullView(boolean forceFullView);
boolean isForceFullView();
}

View file

@ -81,7 +81,7 @@ public class DBTraceProgramViewMemoryTest extends AbstractGhidraHeadlessIntegrat
assertEquals(1, blocks.length);
MemoryBlock blk = blocks[0];
assertSame(blk, vmem.getBlock(io));
assertSame(blk, vmem.getRegionBlock(io));
assertEquals(".io", blk.getName());
assertEquals(b.addr(os, 0x1000), blk.getStart());
assertEquals(b.addr(os, 0x1fff), blk.getEnd());

View file

@ -16,6 +16,7 @@
package ghidra.app.plugin.core.checksums;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.List;
import ghidra.program.model.address.Address;
@ -60,6 +61,11 @@ class MyTestMemoryBlock implements MemoryBlock {
throw new UnsupportedOperationException();
}
@Override
public BigInteger getSizeAsBigInteger() {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
throw new UnsupportedOperationException();

View file

@ -467,17 +467,17 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
// adjust the end index/field because the selection does not
// include the end
int endFieldOffset = endLoc.getFieldNum();
int endIndex = endLoc.getIndex().intValue();
BigInteger endIndex = endLoc.getIndex();
if (endFieldOffset == fieldFactories.length - 1) {
endFieldOffset = 0;
++endIndex;
endIndex = endIndex.add(BigInteger.ONE);
}
else {
++endFieldOffset;
}
fsel.addRange(
new FieldLocation(startLoc.getIndex().intValue(), startLoc.getFieldNum(), 0, 0),
new FieldLocation(startLoc.getIndex(), startLoc.getFieldNum(), 0, 0),
new FieldLocation(endIndex, endFieldOffset, 0, 0));
}
return fsel;

View file

@ -125,7 +125,7 @@ public class ByteViewerLayoutModel implements LayoutModel {
if (index.compareTo(numIndexes) >= 0) {
return null;
}
List<Field> fields = new ArrayList<Field>(8);
List<Field> fields = new ArrayList<Field>(factorys.length);
for (FieldFactory factory : factorys) {
Field field = factory.getField(index);
if (field != null) {

View file

@ -91,14 +91,7 @@ public class MemoryByteBlock implements ByteBlock {
*/
@Override
public BigInteger getLength() {
long size = block.getSize();
if (size < 0) {
return BigInteger.valueOf(size + 0x8000000000000000L)
.subtract(
BigInteger.valueOf(0x8000000000000000L));
}
return BigInteger.valueOf(size);
return block.getSizeAsBigInteger();
}
/**

View file

@ -17,6 +17,7 @@ package ghidra.program.database.mem;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.*;
import db.DBBuffer;
@ -26,6 +27,7 @@ import ghidra.program.database.map.AddressMap;
import ghidra.program.database.map.AddressMapDB;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.*;
import ghidra.util.NumericUtilities;
import ghidra.util.exception.AssertException;
public class MemoryBlockDB implements MemoryBlock {
@ -52,6 +54,7 @@ public class MemoryBlockDB implements MemoryBlock {
/**
* Returns the id for this memory block
*
* @return the id for this memory block
*/
long getID() {
@ -81,6 +84,7 @@ public class MemoryBlockDB implements MemoryBlock {
/**
* Add a block which is mapped onto this block
*
* @param mappedBlock mapped memory block
*/
void addMappedBlock(MemoryBlockDB mappedBlock) {
@ -99,6 +103,7 @@ public class MemoryBlockDB implements MemoryBlock {
/**
* Get collection of blocks which map onto this block.
*
* @return collection of blocks which map onto this block or null if none identified
*/
Collection<MemoryBlockDB> getMappedBlocks() {
@ -144,6 +149,11 @@ public class MemoryBlockDB implements MemoryBlock {
return length;
}
@Override
public BigInteger getSizeAsBigInteger() {
return NumericUtilities.unsignedLongToBigInteger(length);
}
@Override
public String getName() {
String name = record.getString(MemoryMapDBAdapter.NAME_COL);

View file

@ -17,6 +17,7 @@ package ghidra.program.model.mem;
import java.io.InputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.List;
import ghidra.framework.store.LockException;
@ -30,8 +31,8 @@ import ghidra.util.NamingUtilities;
public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* A special EXTERNAL block may be created by certain program loaders (e.g., Elf) to
* act as a stand-in for unknown external symbol locations.
* A special EXTERNAL block may be created by certain program loaders (e.g., Elf) to act as a
* stand-in for unknown external symbol locations.
*/
public static final String EXTERNAL_BLOCK_NAME = "EXTERNAL";
@ -42,19 +43,20 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
public static int EXECUTE = 0x1;
/**
* Returns block permissions as a bit mask.
* Permission bits defined as READ, WRITE, EXECUTE and VOLATILE
* Returns block permissions as a bit mask. Permission bits defined as READ, WRITE, EXECUTE and
* VOLATILE
*/
public int getPermissions();
/**
* Get memory data in the form of an InputStream.
* Null is returned for thos memory blocks which have no data.
* Get memory data in the form of an InputStream. Null is returned for thos memory blocks which
* have no data.
*/
public InputStream getData();
/**
* Return whether addr is contained in this block.
*
* @param addr address
*/
public boolean contains(Address addr);
@ -80,14 +82,22 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
*/
public long getSize();
/**
* Get the number of bytes in this block.
*
* @return the number of bytes in this block as a BigInteger
*/
public BigInteger getSizeAsBigInteger();
/**
* Get the name of this block
*/
public String getName();
/**
* Set the name for this block (See {@link NamingUtilities#isValidName(String)} for
* naming rules). Specified name must not conflict with an address space name.
* Set the name for this block (See {@link NamingUtilities#isValidName(String)} for naming
* rules). Specified name must not conflict with an address space name.
*
* @param name the new name for this block.
* @throws IllegalArgumentException if invalid name specified
* @throws LockException renaming an Overlay block without exclusive access
@ -102,6 +112,7 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* Set the comment associated with this block.
*
* @param comment the comment to associate with this block.
*/
public void setComment(String comment);
@ -113,6 +124,7 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* Sets the read property associated with this block.
*
* @param r the value to set the read property to.
*/
public void setRead(boolean r);
@ -124,6 +136,7 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* Sets the write property associated with this block.
*
* @param w the value to set the write property to.
*/
public void setWrite(boolean w);
@ -135,12 +148,14 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* Sets the execute property associated with this block.
*
* @param e the value to set the execute property to.
*/
public void setExecute(boolean e);
/**
* Sets the read, write, execute permissions on this block
*
* @param read the read permission
* @param write the write permission
* @param execute the execute permission
@ -148,13 +163,14 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
public void setPermissions(boolean read, boolean write, boolean execute);
/**
* Returns the value of the volatile property associated with this block.
* This attribute is generally associated with block of I/O regions of memory.
* Returns the value of the volatile property associated with this block. This attribute is
* generally associated with block of I/O regions of memory.
*/
public boolean isVolatile();
/**
* Sets the volatile property associated with this block.
*
* @param v the value to set the volatile property to.
*/
public void setVolatile(boolean v);
@ -168,48 +184,50 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* Sets the name of the source file that provided the data.
*
* @param sourceName the name of the source file.
*/
public void setSourceName(String sourceName);
/**
* Returns the byte at the given address in this block.
*
* @param addr the address.
* @throws MemoryAccessException if any of the requested bytes are
* uninitialized.
* @throws MemoryAccessException if any of the requested bytes are uninitialized.
* @throws IllegalArgumentException if the Address is not in this block.
*/
public byte getByte(Address addr) throws MemoryAccessException;
/**
* Tries to get b.length bytes from this block at the given address. May
* return fewer bytes if the requested length is beyond the end of the block.
* Tries to get b.length bytes from this block at the given address. May return fewer bytes if
* the requested length is beyond the end of the block.
*
* @param addr the address from which to get the bytes.
* @param b the byte array to populate.
* @return the number of bytes actually populated.
* @throws MemoryAccessException if any of the requested bytes are
* uninitialized.
* @throws MemoryAccessException if any of the requested bytes are uninitialized.
* @throws IllegalArgumentException if the Address is not in this block.
*/
public int getBytes(Address addr, byte[] b) throws MemoryAccessException;
/**
* Tries to get len bytes from this block at the given address and put them
* into the given byte array at the specified offet. May return
* fewer bytes if the requested length is beyond the end of the block.
* Tries to get len bytes from this block at the given address and put them into the given byte
* array at the specified offet. May return fewer bytes if the requested length is beyond the
* end of the block.
*
* @param addr the address from which to get the bytes.
* @param b the byte array to populate.
* @param off the offset into the byte array.
* @param len the number of bytes to get.
* @return the number of bytes actually populated.
* @throws MemoryAccessException if any of the requested bytes are
* uninitialized.
* @throws MemoryAccessException if any of the requested bytes are uninitialized.
* @throws IllegalArgumentException if the Address is not in this block.
*/
public int getBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException;
/**
* Puts the given byte at the given address in this block.
*
* @param addr the address.
* @throws MemoryAccessException if the block is uninitialized
* @throws IllegalArgumentException if the Address is not in this block.
@ -217,9 +235,9 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
public void putByte(Address addr, byte b) throws MemoryAccessException;
/**
* Tries to put b.length bytes from the specified byte array to this block.
* All the bytes may not be put if the requested length is beyond the end of
* the block.
* Tries to put b.length bytes from the specified byte array to this block. All the bytes may
* not be put if the requested length is beyond the end of the block.
*
* @param addr the address of where to put the bytes.
* @param b the byte array containing the bytes to write.
* @return the number of bytes actually written.
@ -229,9 +247,9 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
public int putBytes(Address addr, byte[] b) throws MemoryAccessException;
/**
* Tries to put len bytes from the specified byte array to this block. All
* the bytes may not be written if the requested length is beyond the end of
* the block.
* Tries to put len bytes from the specified byte array to this block. All the bytes may not be
* written if the requested length is beyond the end of the block.
*
* @param addr the address of where to put the bytes.
* @param b the byte array containing the bytes to write.
* @param off the offset into the byte array.
@ -259,6 +277,7 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* Returns true if this is an overlay block (i.e., contained within overlay space).
*
* @return true if this is an overlay block
*/
public boolean isOverlay();
@ -266,21 +285,24 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* Returns true if this memory block is a real loaded block (i.e. RAM) and not a special block
* containing file header data such as debug sections.
*
* @return true if this is a loaded block and not a "special" block such as a file header.
*/
public boolean isLoaded();
/**
* Returns a list of {@link MemoryBlockSourceInfo} objects for this block. A block may consist of
* multiple sequences of bytes from different sources. Each such source of bytes is described
* by its respective SourceInfo object. Blocks may have multiple sources after two or more
* Returns a list of {@link MemoryBlockSourceInfo} objects for this block. A block may consist
* of multiple sequences of bytes from different sources. Each such source of bytes is described
* by its respective SourceInfo object. Blocks may have multiple sources after two or more
* memory blocks have been joined together and the underlying byte sources can't be joined.
*
* @return a list of SourceInfo objects, one for each different source of bytes in this block.
*/
public List<MemoryBlockSourceInfo> getSourceInfos();
/**
* Determine if the specified address is contained within the reserved EXTERNAL block.
*
* @param address address of interest
* @param program
* @return true if address is contained within the reserved EXTERNAL block, else false.

View file

@ -16,15 +16,16 @@
package ghidra.program.model.mem;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.List;
import ghidra.framework.store.LockException;
import ghidra.program.model.address.Address;
/**
* MemoryBlockStub can be extended for use by tests. It throws an UnsupportedOperationException
* for all methods in the MemoryBlock interface. Any method that is needed for your test can then
* be overridden so it can provide its own test implementation and return value.
* MemoryBlockStub can be extended for use by tests. It throws an UnsupportedOperationException for
* all methods in the MemoryBlock interface. Any method that is needed for your test can then be
* overridden so it can provide its own test implementation and return value.
*/
public class MemoryBlockStub implements MemoryBlock {
Address start;
@ -74,6 +75,11 @@ public class MemoryBlockStub implements MemoryBlock {
throw new UnsupportedOperationException();
}
@Override
public BigInteger getSizeAsBigInteger() {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
throw new UnsupportedOperationException();