mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-1447: Added 'View all Memory' override toggle to Debugger.
This commit is contained in:
parent
59402a2951
commit
8b2af5241a
30 changed files with 674 additions and 229 deletions
|
@ -65,5 +65,14 @@
|
||||||
<P>This action is available when the dynamic listing's cursor is at a valid location. It
|
<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
|
selects the region containing that cursor. If the dynamic listing has a selection, it selects
|
||||||
all regions intersecting that selection.</P>
|
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>
|
</BODY>
|
||||||
</HTML>
|
</HTML>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
@ -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 {
|
public abstract class AbstractDebuggerConnectionsNode extends GTreeNode {
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|
|
@ -46,8 +46,14 @@ public class DebuggerMemoryByteViewerComponent extends ByteViewerComponent
|
||||||
List<ColoredFieldSelection> selections) {
|
List<ColoredFieldSelection> selections) {
|
||||||
Color selectionColor = paintContext.getSelectionColor();
|
Color selectionColor = paintContext.getSelectionColor();
|
||||||
Color highlightColor = paintContext.getHighlightColor();
|
Color highlightColor = paintContext.getHighlightColor();
|
||||||
selections.add(new ColoredFieldSelection(getSelection(), selectionColor));
|
FieldSelection selection = getSelection();
|
||||||
selections.add(new ColoredFieldSelection(getHighlight(), highlightColor));
|
if (!selection.isEmpty()) {
|
||||||
|
selections.add(new ColoredFieldSelection(selection, selectionColor));
|
||||||
|
}
|
||||||
|
FieldSelection highlight = getHighlight();
|
||||||
|
if (!highlight.isEmpty()) {
|
||||||
|
selections.add(new ColoredFieldSelection(highlight, highlightColor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,7 @@ import docking.widgets.table.CustomToStringCellRenderer;
|
||||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
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.*;
|
||||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.SelectRowsAction;
|
|
||||||
import ghidra.app.plugin.core.debug.utils.DebouncedRowWrappedEnumeratedColumnTableModel;
|
import ghidra.app.plugin.core.debug.utils.DebouncedRowWrappedEnumeratedColumnTableModel;
|
||||||
import ghidra.app.services.DebuggerListingService;
|
import ghidra.app.services.DebuggerListingService;
|
||||||
import ghidra.app.services.DebuggerTraceManagerService;
|
import ghidra.app.services.DebuggerTraceManagerService;
|
||||||
|
@ -233,6 +232,7 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
|
||||||
|
|
||||||
SelectAddressesAction actionSelectAddresses;
|
SelectAddressesAction actionSelectAddresses;
|
||||||
DockingAction actionSelectRows;
|
DockingAction actionSelectRows;
|
||||||
|
ToggleDockingAction actionForceFullView;
|
||||||
|
|
||||||
public DebuggerRegionsProvider(DebuggerRegionsPlugin plugin) {
|
public DebuggerRegionsProvider(DebuggerRegionsPlugin plugin) {
|
||||||
super(plugin.getTool(), DebuggerResources.TITLE_PROVIDER_REGIONS, plugin.getName(),
|
super(plugin.getTool(), DebuggerResources.TITLE_PROVIDER_REGIONS, plugin.getName(),
|
||||||
|
@ -341,6 +341,11 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
|
||||||
.enabledWhen(ctx -> currentTrace != null)
|
.enabledWhen(ctx -> currentTrace != null)
|
||||||
.onAction(this::activatedSelectCurrent)
|
.onAction(this::activatedSelectCurrent)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstallLocal(this);
|
||||||
|
|
||||||
|
actionForceFullView = ForceFullViewAction.builder(plugin)
|
||||||
|
.enabledWhen(ctx -> currentTrace != null)
|
||||||
|
.onAction(this::activatedForceFullView)
|
||||||
|
.buildAndInstallLocal(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activatedSelectCurrent(ActionContext ignored) {
|
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) {
|
public void setSelectedRegions(Set<TraceMemoryRegion> sel) {
|
||||||
DebuggerResources.setSelectedRows(sel, regionTableModel::getRow, regionTable,
|
DebuggerResources.setSelectedRows(sel, regionTableModel::getRow, regionTable,
|
||||||
regionTableModel, regionFilterPanel);
|
regionTableModel, regionFilterPanel);
|
||||||
|
@ -396,6 +410,16 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
|
||||||
contextChanged();
|
contextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextChanged() {
|
||||||
|
super.contextChanged();
|
||||||
|
if (currentTrace != null) {
|
||||||
|
actionForceFullView.setSelected(currentTrace.getProgramView()
|
||||||
|
.getMemory()
|
||||||
|
.isForceFullView());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void removeOldListeners() {
|
private void removeOldListeners() {
|
||||||
if (currentTrace == null) {
|
if (currentTrace == null) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -716,30 +716,38 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateViewsAddBlock(DBTraceMemoryRegion region) {
|
public void updateViewsAddRegionBlock(DBTraceMemoryRegion region) {
|
||||||
allViews(v -> v.updateMemoryAddBlock(region));
|
allViews(v -> v.updateMemoryAddRegionBlock(region));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateViewsChangeBlockName(DBTraceMemoryRegion region) {
|
public void updateViewsChangeRegionBlockName(DBTraceMemoryRegion region) {
|
||||||
allViews(v -> v.updateMemoryChangeBlockName(region));
|
allViews(v -> v.updateMemoryChangeRegionBlockName(region));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateViewsChangeBlockFlags(DBTraceMemoryRegion region) {
|
public void updateViewsChangeRegionBlockFlags(DBTraceMemoryRegion region) {
|
||||||
allViews(v -> v.updateMemoryChangeBlockFlags(region));
|
allViews(v -> v.updateMemoryChangeRegionBlockFlags(region));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateViewsChangeBlockRange(DBTraceMemoryRegion region,
|
public void updateViewsChangeRegionBlockRange(DBTraceMemoryRegion region,
|
||||||
AddressRange oldRange, AddressRange newRange) {
|
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) {
|
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) {
|
public void updateViewsDeleteRegionBlock(DBTraceMemoryRegion region) {
|
||||||
allViews(v -> v.updateMemoryDeleteBlock(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() {
|
public void updateViewsRefreshBlocks() {
|
||||||
|
|
|
@ -255,6 +255,7 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
||||||
// Only if it succeeds do we store the record
|
// Only if it succeeds do we store the record
|
||||||
DBTraceOverlaySpaceEntry ent = overlayStore.create();
|
DBTraceOverlaySpaceEntry ent = overlayStore.create();
|
||||||
ent.set(space.getName(), base.getName());
|
ent.set(space.getName(), base.getName());
|
||||||
|
trace.updateViewsAddSpaceBlock(space);
|
||||||
return space;
|
return space;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,7 +269,10 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
||||||
}
|
}
|
||||||
overlayStore.delete(exists);
|
overlayStore.delete(exists);
|
||||||
TraceAddressFactory factory = trace.getInternalAddressFactory();
|
TraceAddressFactory factory = trace.getInternalAddressFactory();
|
||||||
|
AddressSpace space = factory.getAddressSpace(name);
|
||||||
|
assert space != null;
|
||||||
factory.removeOverlaySpace(name);
|
factory.removeOverlaySpace(name);
|
||||||
|
trace.updateViewsDeleteSpaceBlock(space);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ public class DBTraceMemoryRegion
|
||||||
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
update(NAME_COLUMN);
|
update(NAME_COLUMN);
|
||||||
space.trace.updateViewsChangeBlockName(this);
|
space.trace.updateViewsChangeRegionBlockName(this);
|
||||||
}
|
}
|
||||||
space.trace.setChanged(
|
space.trace.setChanged(
|
||||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
||||||
|
@ -175,7 +175,7 @@ public class DBTraceMemoryRegion
|
||||||
checkPathConflicts(newLifespan, path);
|
checkPathConflicts(newLifespan, path);
|
||||||
Range<Long> oldLifespan = getLifespan();
|
Range<Long> oldLifespan = getLifespan();
|
||||||
doSetLifespan(newLifespan);
|
doSetLifespan(newLifespan);
|
||||||
space.trace.updateViewsChangeBlockLifespan(this, oldLifespan, newLifespan);
|
space.trace.updateViewsChangeRegionBlockLifespan(this, oldLifespan, newLifespan);
|
||||||
space.trace.setChanged(
|
space.trace.setChanged(
|
||||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.LIFESPAN_CHANGED,
|
new TraceChangeRecord<>(TraceMemoryRegionChangeType.LIFESPAN_CHANGED,
|
||||||
space, this, oldLifespan, newLifespan));
|
space, this, oldLifespan, newLifespan));
|
||||||
|
@ -218,7 +218,7 @@ public class DBTraceMemoryRegion
|
||||||
oldRange = range;
|
oldRange = range;
|
||||||
checkOverlapConflicts(lifespan, newRange);
|
checkOverlapConflicts(lifespan, newRange);
|
||||||
doSetRange(newRange);
|
doSetRange(newRange);
|
||||||
space.trace.updateViewsChangeBlockRange(this, oldRange, newRange);
|
space.trace.updateViewsChangeRegionBlockRange(this, oldRange, newRange);
|
||||||
}
|
}
|
||||||
space.trace.setChanged(
|
space.trace.setChanged(
|
||||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
||||||
|
@ -278,7 +278,7 @@ public class DBTraceMemoryRegion
|
||||||
this.flags.add(f);
|
this.flags.add(f);
|
||||||
}
|
}
|
||||||
update(FLAGS_COLUMN);
|
update(FLAGS_COLUMN);
|
||||||
space.trace.updateViewsChangeBlockFlags(this);
|
space.trace.updateViewsChangeRegionBlockFlags(this);
|
||||||
}
|
}
|
||||||
space.trace.setChanged(
|
space.trace.setChanged(
|
||||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
||||||
|
@ -293,7 +293,7 @@ public class DBTraceMemoryRegion
|
||||||
this.flags.add(f);
|
this.flags.add(f);
|
||||||
}
|
}
|
||||||
update(FLAGS_COLUMN);
|
update(FLAGS_COLUMN);
|
||||||
space.trace.updateViewsChangeBlockFlags(this);
|
space.trace.updateViewsChangeRegionBlockFlags(this);
|
||||||
}
|
}
|
||||||
space.trace.setChanged(
|
space.trace.setChanged(
|
||||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
||||||
|
@ -308,7 +308,7 @@ public class DBTraceMemoryRegion
|
||||||
this.flags.remove(f);
|
this.flags.remove(f);
|
||||||
}
|
}
|
||||||
update(FLAGS_COLUMN);
|
update(FLAGS_COLUMN);
|
||||||
space.trace.updateViewsChangeBlockFlags(this);
|
space.trace.updateViewsChangeRegionBlockFlags(this);
|
||||||
}
|
}
|
||||||
space.trace.setChanged(
|
space.trace.setChanged(
|
||||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
||||||
|
|
|
@ -161,7 +161,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
DBTraceMemoryRegion region =
|
DBTraceMemoryRegion region =
|
||||||
regionMapSpace.put(new ImmutableTraceAddressSnapRange(range, lifespan), null);
|
regionMapSpace.put(new ImmutableTraceAddressSnapRange(range, lifespan), null);
|
||||||
region.set(path, path, flags);
|
region.set(path, path, flags);
|
||||||
trace.updateViewsAddBlock(region);
|
trace.updateViewsAddRegionBlock(region);
|
||||||
trace.setChanged(
|
trace.setChanged(
|
||||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.ADDED, this, region));
|
new TraceChangeRecord<>(TraceMemoryRegionChangeType.ADDED, this, region));
|
||||||
return region;
|
return region;
|
||||||
|
@ -244,7 +244,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||||
regionMapSpace.deleteData(region);
|
regionMapSpace.deleteData(region);
|
||||||
regionCache.remove(region);
|
regionCache.remove(region);
|
||||||
trace.updateViewsDeleteBlock(region);
|
trace.updateViewsDeleteRegionBlock(region);
|
||||||
trace.setChanged(
|
trace.setChanged(
|
||||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.DELETED, this, region));
|
new TraceChangeRecord<>(TraceMemoryRegionChangeType.DELETED, this, region));
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
||||||
DBTraceMemorySpace mem = trace.getMemoryManager().get(this, false);
|
DBTraceMemorySpace mem = trace.getMemoryManager().get(this, false);
|
||||||
if (mem == null) {
|
if (mem == null) {
|
||||||
// TODO: 0-fill instead? Will need to check memory space bounds.
|
// TODO: 0-fill instead? Will need to check memory space bounds.
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return mem.getViewBytes(program.snap, address.add(addressOffset), buffer);
|
return mem.getViewBytes(program.snap, address.add(addressOffset), buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import com.google.common.cache.RemovalNotification;
|
import com.google.common.cache.RemovalNotification;
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ public abstract class AbstractDBTraceProgramViewMemory
|
||||||
protected final DBTraceMemoryManager memoryManager;
|
protected final DBTraceMemoryManager memoryManager;
|
||||||
|
|
||||||
protected AddressSetView addressSet;
|
protected AddressSetView addressSet;
|
||||||
|
protected boolean forceFullView = false;
|
||||||
protected long snap;
|
protected long snap;
|
||||||
|
|
||||||
public AbstractDBTraceProgramViewMemory(DBTraceProgramView program) {
|
public AbstractDBTraceProgramViewMemory(DBTraceProgramView program) {
|
||||||
|
@ -50,16 +52,57 @@ public abstract class AbstractDBTraceProgramViewMemory
|
||||||
setSnap(program.snap);
|
setSnap(program.snap);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void blockRemoved(
|
protected void regionBlockRemoved(
|
||||||
RemovalNotification<DBTraceMemoryRegion, DBTraceProgramViewMemoryBlock> rn) {
|
RemovalNotification<DBTraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> rn) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void spaceBlockRemoved(
|
||||||
|
RemovalNotification<AddressSpace, DBTraceProgramViewMemorySpaceBlock> rn) {
|
||||||
// Nothing
|
// Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void recomputeAddressSet();
|
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) {
|
void setSnap(long snap) {
|
||||||
this.snap = snap;
|
this.snap = snap;
|
||||||
recomputeAddressSet();
|
if (!forceFullView) {
|
||||||
|
recomputeAddressSet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -463,17 +506,23 @@ public abstract class AbstractDBTraceProgramViewMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void addRange(AddressRange range) {
|
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) {
|
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) {
|
protected synchronized void changeRange(AddressRange remove, AddressRange add) {
|
||||||
AddressSet temp = new AddressSet(addressSet);
|
if (!forceFullView) {
|
||||||
temp.delete(remove);
|
AddressSet temp = new AddressSet(addressSet);
|
||||||
temp.add(add);
|
temp.delete(remove);
|
||||||
addressSet = temp;
|
temp.add(add);
|
||||||
|
addressSet = temp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,42 +16,39 @@
|
||||||
package ghidra.trace.database.program;
|
package ghidra.trace.database.program;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
|
||||||
import ghidra.program.database.mem.ByteMappingScheme;
|
import ghidra.program.database.mem.ByteMappingScheme;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.address.AddressRange;
|
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.trace.database.memory.DBTraceMemoryRegion;
|
|
||||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
|
||||||
import ghidra.trace.model.memory.TraceMemorySpaceInputStream;
|
import ghidra.trace.model.memory.TraceMemorySpaceInputStream;
|
||||||
|
import ghidra.util.MathUtilities;
|
||||||
|
|
||||||
// TODO: Proper locking all over here
|
public abstract class AbstractDBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
|
||||||
|
|
||||||
private class DBTraceProgramViewMemoryBlockSourceInfo implements MemoryBlockSourceInfo {
|
private class MyMemoryBlockSourceInfo implements MemoryBlockSourceInfo {
|
||||||
@Override
|
@Override
|
||||||
public long getLength() {
|
public long getLength() {
|
||||||
return region.getLength();
|
return getMemoryBlock().getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getMinAddress() {
|
public Address getMinAddress() {
|
||||||
return region.getMinAddress();
|
return getMemoryBlock().getStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getMaxAddress() {
|
public Address getMaxAddress() {
|
||||||
return region.getMaxAddress();
|
return getMemoryBlock().getEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return "Trace region: " + region;
|
return getInfoDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,12 +78,12 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryBlock getMemoryBlock() {
|
public MemoryBlock getMemoryBlock() {
|
||||||
return DBTraceProgramViewMemoryBlock.this;
|
return AbstractDBTraceProgramViewMemoryBlock.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Address address) {
|
public boolean contains(Address address) {
|
||||||
return region.getRange().contains(address);
|
return getMemoryBlock().contains(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -95,15 +92,26 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final DBTraceProgramView program;
|
protected final DBTraceProgramView program;
|
||||||
private final DBTraceMemoryRegion region;
|
|
||||||
|
|
||||||
private final List<MemoryBlockSourceInfo> info =
|
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.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
|
@Override
|
||||||
|
@ -111,112 +119,40 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
return this.getStart().compareTo(that.getStart());
|
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
|
@Override
|
||||||
public boolean contains(Address addr) {
|
public boolean contains(Address addr) {
|
||||||
return region.getRange().contains(addr);
|
return getAddressRange().contains(addr);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Address getStart() {
|
|
||||||
return region.getRange().getMinAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Address getEnd() {
|
|
||||||
return region.getRange().getMaxAddress();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
return region.getRange().getLength();
|
return getEnd().subtract(getStart()) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public BigInteger getSizeAsBigInteger() {
|
||||||
return region.getName();
|
return getEnd().getOffsetAsBigInteger()
|
||||||
}
|
.subtract(getStart().getOffsetAsBigInteger())
|
||||||
|
.add(BigInteger.ONE);
|
||||||
@Override
|
|
||||||
public void setName(String name) throws LockException {
|
|
||||||
region.setName(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getComment() {
|
public String getComment() {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setComment(String comment) {
|
public void setComment(String comment) {
|
||||||
// TODO Auto-generated method stub
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRead() {
|
public InputStream getData() {
|
||||||
return region.isRead();
|
DBTraceMemorySpace ms = getMemorySpace();
|
||||||
}
|
if (ms == null) {
|
||||||
|
return null;
|
||||||
@Override
|
}
|
||||||
public void setRead(boolean r) {
|
return new TraceMemorySpaceInputStream(program, ms, getAddressRange());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -231,7 +167,7 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte getByte(Address addr) throws MemoryAccessException {
|
public byte getByte(Address addr) throws MemoryAccessException {
|
||||||
AddressRange range = region.getRange();
|
AddressRange range = getAddressRange();
|
||||||
if (!range.contains(addr)) {
|
if (!range.contains(addr)) {
|
||||||
throw new MemoryAccessException();
|
throw new MemoryAccessException();
|
||||||
}
|
}
|
||||||
|
@ -254,7 +190,7 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException {
|
public int getBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException {
|
||||||
AddressRange range = region.getRange();
|
AddressRange range = getAddressRange();
|
||||||
if (!range.contains(addr)) {
|
if (!range.contains(addr)) {
|
||||||
throw new MemoryAccessException();
|
throw new MemoryAccessException();
|
||||||
}
|
}
|
||||||
|
@ -263,7 +199,7 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
if (space == null) {
|
if (space == null) {
|
||||||
throw new MemoryAccessException("Space does not exist");
|
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));
|
return space.getViewBytes(program.snap, addr, ByteBuffer.wrap(b, off, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +217,7 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int putBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException {
|
public int putBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException {
|
||||||
AddressRange range = region.getRange();
|
AddressRange range = getAddressRange();
|
||||||
if (!range.contains(addr)) {
|
if (!range.contains(addr)) {
|
||||||
throw new MemoryAccessException();
|
throw new MemoryAccessException();
|
||||||
}
|
}
|
||||||
|
@ -308,7 +244,8 @@ public class DBTraceProgramViewMemoryBlock implements MemoryBlock {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOverlay() {
|
public boolean isOverlay() {
|
||||||
return false;
|
// TODO: What effect does this have? Does it makes sense for trace "overlays"?
|
||||||
|
return getAddressSpace().isOverlaySpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("<%s on %s at snap=%d>", getClass().getSimpleName(), trace, snap);
|
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);
|
trace.removeTransactionListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMemoryAddBlock(DBTraceMemoryRegion region) {
|
public void updateMemoryAddRegionBlock(DBTraceMemoryRegion region) {
|
||||||
if (!isRegionVisible(region)) {
|
if (!isRegionVisible(region)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memory.updateAddBlock(region);
|
memory.updateAddRegionBlock(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMemoryChangeBlockName(DBTraceMemoryRegion region) {
|
public void updateMemoryChangeRegionBlockName(DBTraceMemoryRegion region) {
|
||||||
if (!isRegionVisible(region)) {
|
if (!isRegionVisible(region)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memory.updateChangeBlockName(region);
|
memory.updateChangeRegionBlockName(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMemoryChangeBlockFlags(DBTraceMemoryRegion region) {
|
public void updateMemoryChangeRegionBlockFlags(DBTraceMemoryRegion region) {
|
||||||
if (!isRegionVisible(region)) {
|
if (!isRegionVisible(region)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memory.updateChangeBlockFlags(region);
|
memory.updateChangeRegionBlockFlags(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMemoryChangeBlockRange(DBTraceMemoryRegion region, AddressRange oldRange,
|
public void updateMemoryChangeRegionBlockRange(DBTraceMemoryRegion region,
|
||||||
|
AddressRange oldRange,
|
||||||
AddressRange newRange) {
|
AddressRange newRange) {
|
||||||
if (!isRegionVisible(region)) {
|
if (!isRegionVisible(region)) {
|
||||||
return;
|
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) {
|
Range<Long> oldLifespan, Range<Long> newLifespan) {
|
||||||
boolean inOld = isRegionVisible(region, oldLifespan);
|
boolean inOld = isRegionVisible(region, oldLifespan);
|
||||||
boolean inNew = isRegionVisible(region, newLifespan);
|
boolean inNew = isRegionVisible(region, newLifespan);
|
||||||
if (inOld && !inNew) {
|
if (inOld && !inNew) {
|
||||||
memory.updateDeleteBlock(region);
|
memory.updateDeleteRegionBlock(region);
|
||||||
}
|
}
|
||||||
if (!inOld && inNew) {
|
if (!inOld && inNew) {
|
||||||
memory.updateAddBlock(region);
|
memory.updateAddRegionBlock(region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMemoryDeleteBlock(DBTraceMemoryRegion region) {
|
public void updateMemoryDeleteRegionBlock(DBTraceMemoryRegion region) {
|
||||||
if (!isRegionVisible(region)) {
|
if (!isRegionVisible(region)) {
|
||||||
return;
|
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() {
|
public void updateMemoryRefreshBlocks() {
|
||||||
|
|
|
@ -27,8 +27,19 @@ import ghidra.trace.database.memory.DBTraceMemoryRegion;
|
||||||
|
|
||||||
public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
||||||
|
|
||||||
private final Map<DBTraceMemoryRegion, DBTraceProgramViewMemoryBlock> blocks =
|
// NB. Keep both per-region and force-full (per-space) block sets ready
|
||||||
CacheBuilder.newBuilder().removalListener(this::blockRemoved).weakValues().build().asMap();
|
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) {
|
public DBTraceProgramViewMemory(DBTraceProgramView program) {
|
||||||
super(program);
|
super(program);
|
||||||
|
@ -64,58 +75,84 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
||||||
addressSet = temp;
|
addressSet = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MemoryBlock getBlock(DBTraceMemoryRegion region) {
|
protected MemoryBlock getRegionBlock(DBTraceMemoryRegion region) {
|
||||||
return blocks.computeIfAbsent(region,
|
return regionBlocks.computeIfAbsent(region,
|
||||||
r -> new DBTraceProgramViewMemoryBlock(program, region));
|
r -> new DBTraceProgramViewMemoryRegionBlock(program, region));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MemoryBlock getSpaceBlock(AddressSpace space) {
|
||||||
|
return spaceBlocks.computeIfAbsent(space,
|
||||||
|
s -> new DBTraceProgramViewMemorySpaceBlock(program, space));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryBlock getBlock(Address addr) {
|
public MemoryBlock getBlock(Address addr) {
|
||||||
|
if (forceFullView) {
|
||||||
|
return getSpaceBlock(addr.getAddressSpace());
|
||||||
|
}
|
||||||
DBTraceMemoryRegion region = getTopRegion(s -> memoryManager.getRegionContaining(s, addr));
|
DBTraceMemoryRegion region = getTopRegion(s -> memoryManager.getRegionContaining(s, addr));
|
||||||
return region == null ? null : getBlock(region);
|
return region == null ? null : getRegionBlock(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryBlock getBlock(String blockName) {
|
public MemoryBlock getBlock(String blockName) {
|
||||||
|
if (forceFullView) {
|
||||||
|
AddressSpace space = program.getAddressFactory().getAddressSpace(blockName);
|
||||||
|
return space == null ? null : getSpaceBlock(space);
|
||||||
|
}
|
||||||
DBTraceMemoryRegion region =
|
DBTraceMemoryRegion region =
|
||||||
getTopRegion(s -> memoryManager.getLiveRegionByPath(s, blockName));
|
getTopRegion(s -> memoryManager.getLiveRegionByPath(s, blockName));
|
||||||
return region == null ? null : getBlock(region);
|
return region == null ? null : getRegionBlock(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryBlock[] getBlocks() {
|
public MemoryBlock[] getBlocks() {
|
||||||
List<MemoryBlock> result = new ArrayList<>();
|
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()));
|
Collections.sort(result, Comparator.comparing(b -> b.getStart()));
|
||||||
return result.toArray(new MemoryBlock[result.size()]);
|
return result.toArray(new MemoryBlock[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAddBlock(DBTraceMemoryRegion region) {
|
public void updateAddRegionBlock(DBTraceMemoryRegion region) {
|
||||||
// TODO: add block to cache?
|
// TODO: add block to cache?
|
||||||
addRange(region.getRange());
|
addRange(region.getRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateChangeBlockName(DBTraceMemoryRegion region) {
|
public void updateChangeRegionBlockName(DBTraceMemoryRegion region) {
|
||||||
// Nothing. Block name is taken from region, uncached
|
// 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
|
// Nothing. Block flags are taken from region, uncached
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateChangeBlockRange(DBTraceMemoryRegion region, AddressRange oldRange,
|
public void updateChangeRegionBlockRange(DBTraceMemoryRegion region, AddressRange oldRange,
|
||||||
AddressRange newRange) {
|
AddressRange newRange) {
|
||||||
// TODO: update cached block? Nothing to update.
|
// TODO: update cached block? Nothing to update.
|
||||||
changeRange(oldRange, newRange);
|
changeRange(oldRange, newRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateDeleteBlock(DBTraceMemoryRegion region) {
|
public void updateDeleteRegionBlock(DBTraceMemoryRegion region) {
|
||||||
blocks.remove(region);
|
regionBlocks.remove(region);
|
||||||
removeRange(region.getRange());
|
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() {
|
public void updateRefreshBlocks() {
|
||||||
blocks.clear();
|
regionBlocks.clear();
|
||||||
|
spaceBlocks.clear();
|
||||||
recomputeAddressSet();
|
recomputeAddressSet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,11 @@ public class DBTraceProgramViewRegisterMemory extends AbstractDBTraceProgramView
|
||||||
space.getAddressSpace().getMaxAddress()));
|
space.getAddressSpace().getMaxAddress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setForceFullView(boolean forceFullView) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void recomputeAddressSet() {
|
protected void recomputeAddressSet() {
|
||||||
// AddressSet is always full space
|
// AddressSet is always full space
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.trace.database.program;
|
package ghidra.trace.database.program;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -144,6 +145,11 @@ public class DBTraceProgramViewRegisterMemoryBlock implements MemoryBlock {
|
||||||
return range.getLength();
|
return range.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getSizeAsBigInteger() {
|
||||||
|
return range.getBigLength();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return REGS_BLOCK_NAME;
|
return REGS_BLOCK_NAME;
|
||||||
|
|
|
@ -28,7 +28,6 @@ import ghidra.program.database.map.AddressMap;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.Memory;
|
|
||||||
import ghidra.program.model.pcode.Varnode;
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import ghidra.program.model.reloc.RelocationTable;
|
import ghidra.program.model.reloc.RelocationTable;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
|
@ -40,6 +39,7 @@ import ghidra.trace.database.thread.DBTraceThread;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||||
import ghidra.trace.model.program.TraceProgramView;
|
import ghidra.trace.model.program.TraceProgramView;
|
||||||
|
import ghidra.trace.model.program.TraceProgramViewMemory;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.trace.util.TraceTimeViewport;
|
import ghidra.trace.util.TraceTimeViewport;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -113,7 +113,7 @@ public class DBTraceProgramViewRegisters implements TraceProgramView {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Memory getMemory() {
|
public TraceProgramViewMemory getMemory() {
|
||||||
return memory;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,13 +37,6 @@ public class DBTraceVariableSnapProgramView extends DBTraceProgramView
|
||||||
super(trace, snap, compilerSpec);
|
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
|
@Override
|
||||||
public void setSnap(long newSnap) {
|
public void setSnap(long newSnap) {
|
||||||
if (this.snap == newSnap) {
|
if (this.snap == newSnap) {
|
||||||
|
|
|
@ -24,6 +24,10 @@ import ghidra.trace.util.TraceTimeViewport;
|
||||||
* View of a trace at a particular time, as a program
|
* View of a trace at a particular time, as a program
|
||||||
*/
|
*/
|
||||||
public interface TraceProgramView extends Program {
|
public interface TraceProgramView extends Program {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
TraceProgramViewMemory getMemory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the trace this view presents
|
* Get the trace this view presents
|
||||||
*
|
*
|
||||||
|
|
|
@ -20,4 +20,8 @@ import ghidra.program.model.mem.Memory;
|
||||||
public interface TraceProgramViewMemory extends Memory, SnapSpecificTraceView {
|
public interface TraceProgramViewMemory extends Memory, SnapSpecificTraceView {
|
||||||
@Override
|
@Override
|
||||||
TraceProgramView getProgram();
|
TraceProgramView getProgram();
|
||||||
|
|
||||||
|
void setForceFullView(boolean forceFullView);
|
||||||
|
|
||||||
|
boolean isForceFullView();
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class DBTraceProgramViewMemoryTest extends AbstractGhidraHeadlessIntegrat
|
||||||
assertEquals(1, blocks.length);
|
assertEquals(1, blocks.length);
|
||||||
|
|
||||||
MemoryBlock blk = blocks[0];
|
MemoryBlock blk = blocks[0];
|
||||||
assertSame(blk, vmem.getBlock(io));
|
assertSame(blk, vmem.getRegionBlock(io));
|
||||||
assertEquals(".io", blk.getName());
|
assertEquals(".io", blk.getName());
|
||||||
assertEquals(b.addr(os, 0x1000), blk.getStart());
|
assertEquals(b.addr(os, 0x1000), blk.getStart());
|
||||||
assertEquals(b.addr(os, 0x1fff), blk.getEnd());
|
assertEquals(b.addr(os, 0x1fff), blk.getEnd());
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package ghidra.app.plugin.core.checksums;
|
package ghidra.app.plugin.core.checksums;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
@ -60,6 +61,11 @@ class MyTestMemoryBlock implements MemoryBlock {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getSizeAsBigInteger() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
|
@ -467,17 +467,17 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
|
||||||
// adjust the end index/field because the selection does not
|
// adjust the end index/field because the selection does not
|
||||||
// include the end
|
// include the end
|
||||||
int endFieldOffset = endLoc.getFieldNum();
|
int endFieldOffset = endLoc.getFieldNum();
|
||||||
int endIndex = endLoc.getIndex().intValue();
|
BigInteger endIndex = endLoc.getIndex();
|
||||||
|
|
||||||
if (endFieldOffset == fieldFactories.length - 1) {
|
if (endFieldOffset == fieldFactories.length - 1) {
|
||||||
endFieldOffset = 0;
|
endFieldOffset = 0;
|
||||||
++endIndex;
|
endIndex = endIndex.add(BigInteger.ONE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
++endFieldOffset;
|
++endFieldOffset;
|
||||||
}
|
}
|
||||||
fsel.addRange(
|
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));
|
new FieldLocation(endIndex, endFieldOffset, 0, 0));
|
||||||
}
|
}
|
||||||
return fsel;
|
return fsel;
|
||||||
|
|
|
@ -125,7 +125,7 @@ public class ByteViewerLayoutModel implements LayoutModel {
|
||||||
if (index.compareTo(numIndexes) >= 0) {
|
if (index.compareTo(numIndexes) >= 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<Field> fields = new ArrayList<Field>(8);
|
List<Field> fields = new ArrayList<Field>(factorys.length);
|
||||||
for (FieldFactory factory : factorys) {
|
for (FieldFactory factory : factorys) {
|
||||||
Field field = factory.getField(index);
|
Field field = factory.getField(index);
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
|
|
|
@ -91,14 +91,7 @@ public class MemoryByteBlock implements ByteBlock {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BigInteger getLength() {
|
public BigInteger getLength() {
|
||||||
|
return block.getSizeAsBigInteger();
|
||||||
long size = block.getSize();
|
|
||||||
if (size < 0) {
|
|
||||||
return BigInteger.valueOf(size + 0x8000000000000000L)
|
|
||||||
.subtract(
|
|
||||||
BigInteger.valueOf(0x8000000000000000L));
|
|
||||||
}
|
|
||||||
return BigInteger.valueOf(size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.program.database.mem;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import db.DBBuffer;
|
import db.DBBuffer;
|
||||||
|
@ -26,6 +27,7 @@ import ghidra.program.database.map.AddressMap;
|
||||||
import ghidra.program.database.map.AddressMapDB;
|
import ghidra.program.database.map.AddressMapDB;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
|
import ghidra.util.NumericUtilities;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
public class MemoryBlockDB implements MemoryBlock {
|
public class MemoryBlockDB implements MemoryBlock {
|
||||||
|
@ -52,6 +54,7 @@ public class MemoryBlockDB implements MemoryBlock {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the id for this memory block
|
* Returns the id for this memory block
|
||||||
|
*
|
||||||
* @return the id for this memory block
|
* @return the id for this memory block
|
||||||
*/
|
*/
|
||||||
long getID() {
|
long getID() {
|
||||||
|
@ -81,6 +84,7 @@ public class MemoryBlockDB implements MemoryBlock {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a block which is mapped onto this block
|
* Add a block which is mapped onto this block
|
||||||
|
*
|
||||||
* @param mappedBlock mapped memory block
|
* @param mappedBlock mapped memory block
|
||||||
*/
|
*/
|
||||||
void addMappedBlock(MemoryBlockDB mappedBlock) {
|
void addMappedBlock(MemoryBlockDB mappedBlock) {
|
||||||
|
@ -99,6 +103,7 @@ public class MemoryBlockDB implements MemoryBlock {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get collection of blocks which map onto this block.
|
* Get collection of blocks which map onto this block.
|
||||||
|
*
|
||||||
* @return collection of blocks which map onto this block or null if none identified
|
* @return collection of blocks which map onto this block or null if none identified
|
||||||
*/
|
*/
|
||||||
Collection<MemoryBlockDB> getMappedBlocks() {
|
Collection<MemoryBlockDB> getMappedBlocks() {
|
||||||
|
@ -144,6 +149,11 @@ public class MemoryBlockDB implements MemoryBlock {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getSizeAsBigInteger() {
|
||||||
|
return NumericUtilities.unsignedLongToBigInteger(length);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
String name = record.getString(MemoryMapDBAdapter.NAME_COL);
|
String name = record.getString(MemoryMapDBAdapter.NAME_COL);
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.program.model.mem;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
|
@ -30,8 +31,8 @@ import ghidra.util.NamingUtilities;
|
||||||
public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special EXTERNAL block may be created by certain program loaders (e.g., Elf) to
|
* A special EXTERNAL block may be created by certain program loaders (e.g., Elf) to act as a
|
||||||
* act as a stand-in for unknown external symbol locations.
|
* stand-in for unknown external symbol locations.
|
||||||
*/
|
*/
|
||||||
public static final String EXTERNAL_BLOCK_NAME = "EXTERNAL";
|
public static final String EXTERNAL_BLOCK_NAME = "EXTERNAL";
|
||||||
|
|
||||||
|
@ -42,20 +43,21 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
||||||
public static int EXECUTE = 0x1;
|
public static int EXECUTE = 0x1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns block permissions as a bit mask.
|
* Returns block permissions as a bit mask. Permission bits defined as READ, WRITE, EXECUTE and
|
||||||
* Permission bits defined as READ, WRITE, EXECUTE and VOLATILE
|
* VOLATILE
|
||||||
*/
|
*/
|
||||||
public int getPermissions();
|
public int getPermissions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get memory data in the form of an InputStream.
|
* Get memory data in the form of an InputStream. Null is returned for thos memory blocks which
|
||||||
* Null is returned for thos memory blocks which have no data.
|
* have no data.
|
||||||
*/
|
*/
|
||||||
public InputStream getData();
|
public InputStream getData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether addr is contained in this block.
|
* Return whether addr is contained in this block.
|
||||||
* @param addr address
|
*
|
||||||
|
* @param addr address
|
||||||
*/
|
*/
|
||||||
public boolean contains(Address addr);
|
public boolean contains(Address addr);
|
||||||
|
|
||||||
|
@ -80,14 +82,22 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
||||||
*/
|
*/
|
||||||
public long getSize();
|
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
|
* Get the name of this block
|
||||||
*/
|
*/
|
||||||
public String getName();
|
public String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name for this block (See {@link NamingUtilities#isValidName(String)} for
|
* Set the name for this block (See {@link NamingUtilities#isValidName(String)} for naming
|
||||||
* naming rules). Specified name must not conflict with an address space name.
|
* rules). Specified name must not conflict with an address space name.
|
||||||
|
*
|
||||||
* @param name the new name for this block.
|
* @param name the new name for this block.
|
||||||
* @throws IllegalArgumentException if invalid name specified
|
* @throws IllegalArgumentException if invalid name specified
|
||||||
* @throws LockException renaming an Overlay block without exclusive access
|
* @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.
|
* Set the comment associated with this block.
|
||||||
|
*
|
||||||
* @param comment the comment to associate with this block.
|
* @param comment the comment to associate with this block.
|
||||||
*/
|
*/
|
||||||
public void setComment(String comment);
|
public void setComment(String comment);
|
||||||
|
@ -113,6 +124,7 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the read property associated with this block.
|
* Sets the read property associated with this block.
|
||||||
|
*
|
||||||
* @param r the value to set the read property to.
|
* @param r the value to set the read property to.
|
||||||
*/
|
*/
|
||||||
public void setRead(boolean r);
|
public void setRead(boolean r);
|
||||||
|
@ -124,6 +136,7 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the write property associated with this block.
|
* Sets the write property associated with this block.
|
||||||
|
*
|
||||||
* @param w the value to set the write property to.
|
* @param w the value to set the write property to.
|
||||||
*/
|
*/
|
||||||
public void setWrite(boolean w);
|
public void setWrite(boolean w);
|
||||||
|
@ -135,12 +148,14 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the execute property associated with this block.
|
* Sets the execute property associated with this block.
|
||||||
|
*
|
||||||
* @param e the value to set the execute property to.
|
* @param e the value to set the execute property to.
|
||||||
*/
|
*/
|
||||||
public void setExecute(boolean e);
|
public void setExecute(boolean e);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the read, write, execute permissions on this block
|
* Sets the read, write, execute permissions on this block
|
||||||
|
*
|
||||||
* @param read the read permission
|
* @param read the read permission
|
||||||
* @param write the write permission
|
* @param write the write permission
|
||||||
* @param execute the execute 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);
|
public void setPermissions(boolean read, boolean write, boolean execute);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value of the volatile property associated with this block.
|
* Returns the value of the volatile property associated with this block. This attribute is
|
||||||
* This attribute is generally associated with block of I/O regions of memory.
|
* generally associated with block of I/O regions of memory.
|
||||||
*/
|
*/
|
||||||
public boolean isVolatile();
|
public boolean isVolatile();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the volatile property associated with this block.
|
* Sets the volatile property associated with this block.
|
||||||
|
*
|
||||||
* @param v the value to set the volatile property to.
|
* @param v the value to set the volatile property to.
|
||||||
*/
|
*/
|
||||||
public void setVolatile(boolean v);
|
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.
|
* Sets the name of the source file that provided the data.
|
||||||
|
*
|
||||||
* @param sourceName the name of the source file.
|
* @param sourceName the name of the source file.
|
||||||
*/
|
*/
|
||||||
public void setSourceName(String sourceName);
|
public void setSourceName(String sourceName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the byte at the given address in this block.
|
* Returns the byte at the given address in this block.
|
||||||
|
*
|
||||||
* @param addr the address.
|
* @param addr the address.
|
||||||
* @throws MemoryAccessException if any of the requested bytes are
|
* @throws MemoryAccessException if any of the requested bytes are uninitialized.
|
||||||
* uninitialized.
|
|
||||||
* @throws IllegalArgumentException if the Address is not in this block.
|
* @throws IllegalArgumentException if the Address is not in this block.
|
||||||
*/
|
*/
|
||||||
public byte getByte(Address addr) throws MemoryAccessException;
|
public byte getByte(Address addr) throws MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to get b.length bytes from this block at the given address. May
|
* Tries to get b.length bytes from this block at the given address. May return fewer bytes if
|
||||||
* return fewer bytes if the requested length is beyond the end of the block.
|
* the requested length is beyond the end of the block.
|
||||||
|
*
|
||||||
* @param addr the address from which to get the bytes.
|
* @param addr the address from which to get the bytes.
|
||||||
* @param b the byte array to populate.
|
* @param b the byte array to populate.
|
||||||
* @return the number of bytes actually populated.
|
* @return the number of bytes actually populated.
|
||||||
* @throws MemoryAccessException if any of the requested bytes are
|
* @throws MemoryAccessException if any of the requested bytes are uninitialized.
|
||||||
* uninitialized.
|
|
||||||
* @throws IllegalArgumentException if the Address is not in this block.
|
* @throws IllegalArgumentException if the Address is not in this block.
|
||||||
*/
|
*/
|
||||||
public int getBytes(Address addr, byte[] b) throws MemoryAccessException;
|
public int getBytes(Address addr, byte[] b) throws MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to get len bytes from this block at the given address and put them
|
* Tries to get len bytes from this block at the given address and put them into the given byte
|
||||||
* into the given byte array at the specified offet. May return
|
* array at the specified offet. May return fewer bytes if the requested length is beyond the
|
||||||
* fewer bytes if the requested length is beyond the end of the block.
|
* end of the block.
|
||||||
|
*
|
||||||
* @param addr the address from which to get the bytes.
|
* @param addr the address from which to get the bytes.
|
||||||
* @param b the byte array to populate.
|
* @param b the byte array to populate.
|
||||||
* @param off the offset into the byte array.
|
* @param off the offset into the byte array.
|
||||||
* @param len the number of bytes to get.
|
* @param len the number of bytes to get.
|
||||||
* @return the number of bytes actually populated.
|
* @return the number of bytes actually populated.
|
||||||
* @throws MemoryAccessException if any of the requested bytes are
|
* @throws MemoryAccessException if any of the requested bytes are uninitialized.
|
||||||
* uninitialized.
|
|
||||||
* @throws IllegalArgumentException if the Address is not in this block.
|
* @throws IllegalArgumentException if the Address is not in this block.
|
||||||
*/
|
*/
|
||||||
public int getBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException;
|
public int getBytes(Address addr, byte[] b, int off, int len) throws MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the given byte at the given address in this block.
|
* Puts the given byte at the given address in this block.
|
||||||
|
*
|
||||||
* @param addr the address.
|
* @param addr the address.
|
||||||
* @throws MemoryAccessException if the block is uninitialized
|
* @throws MemoryAccessException if the block is uninitialized
|
||||||
* @throws IllegalArgumentException if the Address is not in this block.
|
* @throws IllegalArgumentException if the Address is not in this block.
|
||||||
|
@ -217,26 +235,26 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
||||||
public void putByte(Address addr, byte b) throws MemoryAccessException;
|
public void putByte(Address addr, byte b) throws MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to put b.length bytes from the specified byte array to this block.
|
* Tries to put b.length bytes from the specified byte array to this block. All the bytes may
|
||||||
* All the bytes may not be put if the requested length is beyond the end of
|
* not be put if the requested length is beyond the end of the block.
|
||||||
* the block.
|
*
|
||||||
* @param addr the address of where to put the bytes.
|
* @param addr the address of where to put the bytes.
|
||||||
* @param b the byte array containing the bytes to write.
|
* @param b the byte array containing the bytes to write.
|
||||||
* @return the number of bytes actually written.
|
* @return the number of bytes actually written.
|
||||||
* @throws MemoryAccessException if the block is uninitialized
|
* @throws MemoryAccessException if the block is uninitialized
|
||||||
* @throws IllegalArgumentException if the Address is not in this block.
|
* @throws IllegalArgumentException if the Address is not in this block.
|
||||||
*/
|
*/
|
||||||
public int putBytes(Address addr, byte[] b) throws MemoryAccessException;
|
public int putBytes(Address addr, byte[] b) throws MemoryAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to put len bytes from the specified byte array to this block. All
|
* Tries to put len bytes from the specified byte array to this block. All the bytes may not be
|
||||||
* the bytes may not be written if the requested length is beyond the end of
|
* written if the requested length is beyond the end of the block.
|
||||||
* the block.
|
*
|
||||||
* @param addr the address of where to put the bytes.
|
* @param addr the address of where to put the bytes.
|
||||||
* @param b the byte array containing the bytes to write.
|
* @param b the byte array containing the bytes to write.
|
||||||
* @param off the offset into the byte array.
|
* @param off the offset into the byte array.
|
||||||
* @param len the number of bytes to write.
|
* @param len the number of bytes to write.
|
||||||
* @return the number of bytes actually written.
|
* @return the number of bytes actually written.
|
||||||
* @throws MemoryAccessException if the block is uninitialized
|
* @throws MemoryAccessException if the block is uninitialized
|
||||||
* @throws IllegalArgumentException if the Address is not in this block.
|
* @throws IllegalArgumentException if the Address is not in this block.
|
||||||
*/
|
*/
|
||||||
|
@ -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).
|
* Returns true if this is an overlay block (i.e., contained within overlay space).
|
||||||
|
*
|
||||||
* @return true if this is an overlay block
|
* @return true if this is an overlay block
|
||||||
*/
|
*/
|
||||||
public boolean isOverlay();
|
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
|
* 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.
|
* 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.
|
* @return true if this is a loaded block and not a "special" block such as a file header.
|
||||||
*/
|
*/
|
||||||
public boolean isLoaded();
|
public boolean isLoaded();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of {@link MemoryBlockSourceInfo} objects for this block. A block may consist of
|
* Returns a list of {@link MemoryBlockSourceInfo} objects for this block. A block may consist
|
||||||
* multiple sequences of bytes from different sources. Each such source of bytes is described
|
* 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
|
* 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.
|
* 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.
|
* @return a list of SourceInfo objects, one for each different source of bytes in this block.
|
||||||
*/
|
*/
|
||||||
public List<MemoryBlockSourceInfo> getSourceInfos();
|
public List<MemoryBlockSourceInfo> getSourceInfos();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the specified address is contained within the reserved EXTERNAL block.
|
* Determine if the specified address is contained within the reserved EXTERNAL block.
|
||||||
|
*
|
||||||
* @param address address of interest
|
* @param address address of interest
|
||||||
* @param program
|
* @param program
|
||||||
* @return true if address is contained within the reserved EXTERNAL block, else false.
|
* @return true if address is contained within the reserved EXTERNAL block, else false.
|
||||||
|
|
|
@ -16,15 +16,16 @@
|
||||||
package ghidra.program.model.mem;
|
package ghidra.program.model.mem;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MemoryBlockStub can be extended for use by tests. It throws an UnsupportedOperationException
|
* MemoryBlockStub can be extended for use by tests. It throws an UnsupportedOperationException for
|
||||||
* for all methods in the MemoryBlock interface. Any method that is needed for your test can then
|
* all methods in the MemoryBlock interface. Any method that is needed for your test can then be
|
||||||
* be overridden so it can provide its own test implementation and return value.
|
* overridden so it can provide its own test implementation and return value.
|
||||||
*/
|
*/
|
||||||
public class MemoryBlockStub implements MemoryBlock {
|
public class MemoryBlockStub implements MemoryBlock {
|
||||||
Address start;
|
Address start;
|
||||||
|
@ -74,6 +75,11 @@ public class MemoryBlockStub implements MemoryBlock {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigInteger getSizeAsBigInteger() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue