mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-08-28 13:30:21 +00:00
Merge remote-tracking branch 'origin/GP-1890_Dan_memoryBytesDiffColoring--SQUASHED'
This commit is contained in:
commit
5ee752891b
|
@ -0,0 +1,64 @@
|
|||
/* ###
|
||||
* 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.app.plugin.core.debug.gui.memory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
public class CachedBytePage {
|
||||
private boolean valid = true;
|
||||
private DebuggerCoordinates coordinates;
|
||||
private Address start;
|
||||
private byte[] page = new byte[4096];
|
||||
private ByteBuffer buf = ByteBuffer.wrap(page);
|
||||
|
||||
public byte getByte(DebuggerCoordinates coordinates, Address address) {
|
||||
long offset;
|
||||
if (!valid || this.coordinates == null || !this.coordinates.equals(coordinates) ||
|
||||
start == null || !start.hasSameAddressSpace(address)) {
|
||||
offset = refresh(coordinates, address);
|
||||
}
|
||||
else {
|
||||
offset = address.subtract(start);
|
||||
if (offset < 0 || 4096 <= offset) {
|
||||
offset = refresh(coordinates, address);
|
||||
}
|
||||
}
|
||||
return page[(int) offset];
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
private long refresh(DebuggerCoordinates coordinates, Address address) {
|
||||
valid = false;
|
||||
buf.clear();
|
||||
Address min = address.getAddressSpace().getMinAddress();
|
||||
start = address.subtractWrap(page.length / 2);
|
||||
|
||||
if (start.compareTo(min) < 0 || start.compareTo(address) > 0) {
|
||||
start = min;
|
||||
}
|
||||
coordinates.getTrace()
|
||||
.getMemoryManager()
|
||||
.getViewBytes(coordinates.getViewSnap(), start, buf);
|
||||
valid = true;
|
||||
return address.subtract(start);
|
||||
}
|
||||
}
|
|
@ -47,7 +47,10 @@ import ghidra.program.model.mem.MemoryBlock;
|
|||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.Trace.TraceMemoryBytesChangeType;
|
||||
import ghidra.trace.model.TraceDomainObjectListener;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
import ghidra.util.Swing;
|
||||
|
||||
public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvider {
|
||||
|
@ -75,6 +78,19 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
return true;
|
||||
}
|
||||
|
||||
protected class ListenerForChanges extends TraceDomainObjectListener {
|
||||
public ListenerForChanges() {
|
||||
listenFor(TraceMemoryBytesChangeType.CHANGED, this::bytesChanged);
|
||||
}
|
||||
|
||||
private void bytesChanged(TraceAddressSpace space) {
|
||||
if (space.getAddressSpace().isMemorySpace()) {
|
||||
currCache.invalidate();
|
||||
prevCache.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class ForMemoryBytesGoToTrait extends DebuggerGoToTrait {
|
||||
public ForMemoryBytesGoToTrait() {
|
||||
super(DebuggerMemoryBytesProvider.this.tool, DebuggerMemoryBytesProvider.this.plugin,
|
||||
|
@ -151,7 +167,13 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
protected AutoReadMemorySpec autoReadMemorySpec = defaultReadMemorySpec;
|
||||
// TODO: followsCurrentSnap?
|
||||
|
||||
private final ListenerForChanges listenerForChanges = new ListenerForChanges();
|
||||
|
||||
DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
|
||||
private DebuggerCoordinates previous = DebuggerCoordinates.NOWHERE;
|
||||
|
||||
private final CachedBytePage currCache = new CachedBytePage();
|
||||
private final CachedBytePage prevCache = new CachedBytePage();
|
||||
|
||||
protected final boolean isMainViewer;
|
||||
|
||||
|
@ -174,6 +196,27 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
setHelpLocation(DebuggerResources.HELP_PROVIDER_MEMORY_BYTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBlockChangeManager newByteBlockChangeManager(ProgramByteBlockSet blockSet,
|
||||
ByteBlockChangeManager bbcm) {
|
||||
return new ByteBlockChangeManager(blockSet, bbcm) {
|
||||
@Override
|
||||
protected boolean isChanged(ByteBlock block, BigInteger offset, int unitByteSize) {
|
||||
if (super.isChanged(block, offset, unitByteSize)) {
|
||||
return true;
|
||||
}
|
||||
if (previous.getTrace() != current.getTrace()) {
|
||||
return false;
|
||||
}
|
||||
Address address = blockSet.getAddress(block, offset);
|
||||
if (address == null) {
|
||||
return false;
|
||||
}
|
||||
return currCache.getByte(current, address) != prevCache.getByte(previous, address);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProgramByteBlockSet newByteBlockSet(ByteBlockChangeManager changeManager) {
|
||||
if (program == null) {
|
||||
|
@ -304,6 +347,18 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
return result;
|
||||
}
|
||||
|
||||
protected void removeOldListeners() {
|
||||
if (current.getTrace() != null) {
|
||||
current.getTrace().removeListener(listenerForChanges);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addNewListeners() {
|
||||
if (current.getTrace() != null) {
|
||||
current.getTrace().addListener(listenerForChanges);
|
||||
}
|
||||
}
|
||||
|
||||
protected DebuggerCoordinates adjustCoordinates(DebuggerCoordinates coordinates) {
|
||||
if (followsCurrentThread) {
|
||||
return coordinates;
|
||||
|
@ -318,7 +373,10 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
current = coordinates;
|
||||
return;
|
||||
}
|
||||
previous = current;
|
||||
removeOldListeners();
|
||||
current = coordinates;
|
||||
addNewListeners();
|
||||
doSetProgram(current.getView());
|
||||
goToTrait.goToCoordinates(coordinates);
|
||||
trackingTrait.goToCoordinates(coordinates);
|
||||
|
|
|
@ -39,20 +39,12 @@ public class ByteBlockChangeManager {
|
|||
private static String OLD_VALUE = "OldValue";
|
||||
private static String NEW_VALUE = "NewValue";
|
||||
|
||||
private int dummy = 4;
|
||||
|
||||
/**
|
||||
* Construct new change manager.
|
||||
*/
|
||||
ByteBlockChangeManager(ProgramByteBlockSet blockSet) {
|
||||
protected ByteBlockChangeManager(ProgramByteBlockSet blockSet, ByteBlockChangeManager bbcm) {
|
||||
this.blockSet = blockSet;
|
||||
changeList = new ArrayList<ByteEditInfo>(3);
|
||||
}
|
||||
|
||||
ByteBlockChangeManager(ProgramByteBlockSet blockSet, ByteBlockChangeManager bbcm) {
|
||||
|
||||
this.blockSet = blockSet;
|
||||
changeList = bbcm.changeList;
|
||||
changeList = bbcm == null ? new ArrayList<>() : bbcm.changeList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,7 +53,7 @@ public class ByteBlockChangeManager {
|
|||
* @param edit edit object that has the old value and new value
|
||||
*
|
||||
*/
|
||||
void add(ByteEditInfo edit) {
|
||||
protected void add(ByteEditInfo edit) {
|
||||
byte[] oldValue = edit.getOldValue();
|
||||
byte[] newValue = edit.getNewValue();
|
||||
|
||||
|
@ -127,7 +119,7 @@ public class ByteBlockChangeManager {
|
|||
*
|
||||
* @return boolean true if an offset in the range was found
|
||||
*/
|
||||
boolean isChanged(ByteBlock block, BigInteger offset, int unitByteSize) {
|
||||
protected boolean isChanged(ByteBlock block, BigInteger offset, int unitByteSize) {
|
||||
Address blockAddr = blockSet.getBlockStart(block);
|
||||
for (int i = 0; i < unitByteSize; i++) {
|
||||
|
||||
|
|
|
@ -46,12 +46,7 @@ public class ProgramByteBlockSet implements ByteBlockSet {
|
|||
|
||||
this.provider = provider;
|
||||
this.program = program;
|
||||
if (bbcm == null) {
|
||||
this.bbcm = new ByteBlockChangeManager(this);
|
||||
}
|
||||
else {
|
||||
this.bbcm = new ByteBlockChangeManager(this, bbcm);
|
||||
}
|
||||
this.bbcm = provider.newByteBlockChangeManager(this, bbcm);
|
||||
|
||||
newMemoryBlocks();
|
||||
}
|
||||
|
@ -204,8 +199,7 @@ public class ProgramByteBlockSet implements ByteBlockSet {
|
|||
/**
|
||||
* Get the address for the given block and offset.
|
||||
*/
|
||||
protected Address getAddress(ByteBlock block, BigInteger offset) {
|
||||
|
||||
public Address getAddress(ByteBlock block, BigInteger offset) {
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
if (blocks[i] != block) {
|
||||
continue;
|
||||
|
|
|
@ -537,7 +537,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
|||
event.containsEvent(DomainObject.DO_DOMAIN_FILE_CHANGED)) {
|
||||
// drop all changes
|
||||
|
||||
blockSet.setByteBlockChangeManager(new ByteBlockChangeManager(blockSet));
|
||||
blockSet.setByteBlockChangeManager(newByteBlockChangeManager(blockSet, null));
|
||||
updateManager.update();
|
||||
}
|
||||
}
|
||||
|
@ -563,6 +563,11 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
|||
}
|
||||
}
|
||||
|
||||
protected ByteBlockChangeManager newByteBlockChangeManager(ProgramByteBlockSet blockSet,
|
||||
ByteBlockChangeManager bbcm) {
|
||||
return new ByteBlockChangeManager(blockSet, bbcm);
|
||||
}
|
||||
|
||||
protected ProgramByteBlockSet newByteBlockSet(ByteBlockChangeManager changeManager) {
|
||||
if (program == null) {
|
||||
return null;
|
||||
|
|
|
@ -125,7 +125,7 @@ public class ByteViewerPlugin1Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testOpenProgramNoMemory() throws Exception {
|
||||
tool.removePlugins(new Plugin[] { cbPlugin });
|
||||
tool.removePlugins(List.of(cbPlugin));
|
||||
|
||||
runSwing(() -> {
|
||||
ProgramManager pm = tool.getService(ProgramManager.class);
|
||||
|
|
Loading…
Reference in a new issue