1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

[230262] Implement Memory Change Trails

This commit is contained in:
Ted Williams 2008-05-21 05:11:09 +00:00
parent 237bb02706
commit c289fa0b9b
8 changed files with 248 additions and 104 deletions

View file

@ -17,6 +17,7 @@ import java.math.BigInteger;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.MemoryByte;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
@ -102,8 +103,8 @@ public class DataPane extends AbstractPane
}
//else
{
if(bytes[i] instanceof TraditionalMemoryByte)
bytesToSet[i].setEdited(((TraditionalMemoryByte) bytes[i]).isEdited());
// if(bytes[i] instanceof TraditionalMemoryByte)
// bytesToSet[i].setEdited(((TraditionalMemoryByte) bytes[i]).isEdited());
bytesToSet[i].setChanged(bytes[i].isChanged());
}
}
@ -272,7 +273,7 @@ public class DataPane extends AbstractPane
* fRendering.getColumnCount() + col)
* fRendering.getAddressesPerColumn()));
MemoryByte bytes[] = fRendering.getBytes(cellAddress,
TraditionalMemoryByte bytes[] = fRendering.getBytes(cellAddress,
fRendering.getBytesPerColumn());
if(fRendering.getSelection().isSelected(cellAddress))
@ -293,7 +294,6 @@ public class DataPane extends AbstractPane
// Allow subclasses to override this method to do their own coloring
applyCustomColor(gc, bytes, col);
}
gc.drawText(getCellText(bytes), cellWidth * col
@ -337,31 +337,46 @@ public class DataPane extends AbstractPane
}
// Allow subclasses to override this method to do their own coloring
protected void applyCustomColor(GC gc, MemoryByte bytes[], int col)
protected void applyCustomColor(GC gc, TraditionalMemoryByte bytes[], int col)
{
// TODO consider adding finer granularity?
boolean anyByteChanged = false;
for(int n = 0; n < bytes.length && !anyByteChanged; n++)
if(bytes[n].isChanged())
anyByteChanged = true;
// TODO consider adding finer granularity?
boolean anyByteEditing = false;
for(int n = 0; n < bytes.length && !anyByteEditing; n++)
if(bytes[n] instanceof TraditionalMemoryByte)
if(((TraditionalMemoryByte) bytes[n]).isEdited())
anyByteEditing = true;
// TODO consider adding finer granularity?
boolean anyByteEditing = false;
for(int n = 0; n < bytes.length && !anyByteEditing; n++)
if(bytes[n] instanceof TraditionalMemoryByte)
if(((TraditionalMemoryByte) bytes[n]).isEdited())
anyByteEditing = true;
if(anyByteEditing)
gc.setForeground(fRendering.getTraditionalRendering().getColorEdit());
else if(anyByteChanged)
gc.setForeground(fRendering.getTraditionalRendering().getColorChanged());
else if(isOdd(col))
if(isOdd(col))
gc.setForeground(fRendering.getTraditionalRendering().getColorText());
else
gc.setForeground(fRendering.getTraditionalRendering().getColorTextAlternate());
gc.setBackground(fRendering.getTraditionalRendering().getColorBackground());
if(anyByteEditing)
{
gc.setForeground(fRendering.getTraditionalRendering().getColorEdit());
}
else
{
boolean isColored = false;
for(int i = 0; i < fRendering.getHistoryDepth() && !isColored; i++)
{
// TODO consider adding finer granularity?
for(int n = 0; n < bytes.length; n++)
{
if(bytes[n].isChanged(i))
{
if(i == 0)
gc.setForeground(fRendering.getTraditionalRendering().getColorsChanged()[i]);
else
gc.setBackground(fRendering.getTraditionalRendering().getColorsChanged()[i]);
isColored = true;
break;
}
}
}
}
}
}

View file

@ -9,9 +9,9 @@ public interface IViewportCache {
public void dispose();
public void refresh();
public MemoryByte[] getBytes(BigInteger address, int bytesRequested) throws DebugException;
public TraditionalMemoryByte[] getBytes(BigInteger address, int bytesRequested) throws DebugException;
public void archiveDeltas();
public void setEditedValue(BigInteger address, MemoryByte[] bytes);
public void setEditedValue(BigInteger address, TraditionalMemoryByte[] bytes);
public void clearEditBuffer();
public void writeEditBuffer();
public boolean containsEditedCell(BigInteger address);

View file

@ -32,6 +32,7 @@ import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.debug.internal.ui.views.memory.MemoryViewUtil;
import org.eclipse.debug.internal.ui.views.memory.renderings.GoToAddressComposite;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
@ -106,7 +107,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
private boolean fIsTargetLittleEndian = false;
private boolean fIsDisplayLittleEndian = false;
// constants used to identify radix
public final static int RADIX_HEX = 1;
@ -482,6 +483,16 @@ public class Rendering extends Composite implements IDebugEventSetListener
{
return fSelection;
}
protected int getHistoryDepth()
{
return fViewportCache.getHistoryDepth();
}
protected void setHistoryDepth(int depth)
{
fViewportCache.setHistoryDepth(depth);
}
public void logError(String message, Exception e)
{
@ -609,7 +620,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
return fViewportCache;
}
public MemoryByte[] getBytes(BigInteger address, int bytes)
public TraditionalMemoryByte[] getBytes(BigInteger address, int bytes)
throws DebugException
{
return getViewportCache().getBytes(address, bytes);
@ -652,7 +663,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
}
return false;
}
}
}
@ -662,7 +673,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
BigInteger end;
MemoryByte[] bytes;
TraditionalMemoryByte[] bytes;
public MemoryUnit clone()
{
@ -670,9 +681,9 @@ public class Rendering extends Composite implements IDebugEventSetListener
b.start = this.start;
b.end = this.end;
b.bytes = new MemoryByte[this.bytes.length];
b.bytes = new TraditionalMemoryByte[this.bytes.length];
for(int i = 0; i < this.bytes.length; i++)
b.bytes[i] = new MemoryByte(this.bytes[i].getValue());
b.bytes[i] = new TraditionalMemoryByte(this.bytes[i].getValue());
return b;
}
@ -694,8 +705,10 @@ public class Rendering extends Composite implements IDebugEventSetListener
protected MemoryUnit fCache = null;
protected MemoryUnit fHistoryCache = null;
protected MemoryUnit fHistoryCache[] = new MemoryUnit[0];
protected int fHistoryDepth = 0;
public ViewportCache()
{
start();
@ -709,6 +722,17 @@ public class Rendering extends Composite implements IDebugEventSetListener
this.notify();
}
}
public int getHistoryDepth()
{
return fHistoryDepth;
}
public void setHistoryDepth(int depth)
{
fHistoryDepth = depth;
fHistoryCache = new MemoryUnit[fHistoryDepth];
}
public void refresh()
{
@ -737,8 +761,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
private void queueRequest(BigInteger startAddress, BigInteger endAddress)
{
AddressPair pair = new AddressPair(startAddress, endAddress);
if(!pair.equals(fLastQueued))
queue(pair);
queue(pair);
}
private void queueRequestArchiveDeltas()
@ -751,8 +774,11 @@ public class Rendering extends Composite implements IDebugEventSetListener
{
synchronized(fQueue)
{
fQueue.addElement(element);
fLastQueued = element;
if(!(fQueue.size() > 0 && element.equals(fLastQueued)))
{
fQueue.addElement(element);
fLastQueued = element;
}
}
synchronized(this)
{
@ -789,7 +815,10 @@ public class Rendering extends Composite implements IDebugEventSetListener
}
if(archiveDeltas)
{
fHistoryCache = fCache.clone();
for(int i = fViewportCache.getHistoryDepth() - 1; i > 0; i--)
fHistoryCache[i] = fHistoryCache[i - 1];
fHistoryCache[0] = fCache.clone();
}
else if(pair != null)
{
@ -837,9 +866,9 @@ public class Rendering extends Composite implements IDebugEventSetListener
final MemoryByte readBytes[] = memoryBlock
.getBytesFromAddress(startAddress, units);
MemoryByte cachedBytes[] = new MemoryByte[readBytes.length];
TraditionalMemoryByte cachedBytes[] = new TraditionalMemoryByte[readBytes.length];
for(int i = 0; i < readBytes.length; i++)
cachedBytes[i] = new MemoryByte(readBytes[i].getValue(), readBytes[i].getFlags());
cachedBytes[i] = new TraditionalMemoryByte(readBytes[i].getValue(), readBytes[i].getFlags());
// derive the target endian from the read MemoryBytes.
if (cachedBytes.length > 0) {
@ -855,7 +884,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
if(addressableSize.compareTo(BigInteger.ONE) != 0)
{
int unitSize = addressableSize.intValue();
MemoryByte cachedBytesAsByteSequence[] = new MemoryByte[cachedBytes.length];
TraditionalMemoryByte cachedBytesAsByteSequence[] = new TraditionalMemoryByte[cachedBytes.length];
for(int unit = 0; unit < units; unit++)
{
for(int unitbyte = 0; unitbyte < unitSize; unitbyte++)
@ -867,40 +896,43 @@ public class Rendering extends Composite implements IDebugEventSetListener
}
}
final MemoryByte[] cachedBytesFinal = cachedBytes;
final TraditionalMemoryByte[] cachedBytesFinal = cachedBytes;
Display.getDefault().asyncExec(new Runnable()
{
public void run()
{
// generate deltas
if(fHistoryCache != null && fHistoryCache.isValid())
{
BigInteger maxStart = startAddress
.max(fHistoryCache.start);
BigInteger minEnd = endAddress
.min(fHistoryCache.end).subtract(
BigInteger.valueOf(1));
BigInteger overlapLength = minEnd
.subtract(maxStart);
if(overlapLength.compareTo(BigInteger.valueOf(0)) > 0)
{
// there is overlap
int offsetIntoOld = maxStart.subtract(
fHistoryCache.start).intValue();
int offsetIntoNew = maxStart.subtract(
startAddress).intValue();
for(int i = overlapLength.intValue(); i >= 0; i--)
{
cachedBytesFinal[offsetIntoNew + i]
.setChanged(cachedBytesFinal[offsetIntoNew
+ i].getValue() != fHistoryCache.bytes[offsetIntoOld
+ i].getValue());
}
}
}
for(int historyIndex = 0; historyIndex < getHistoryDepth(); historyIndex++)
{
if(fHistoryCache[historyIndex] != null && fHistoryCache[historyIndex].isValid())
{
BigInteger maxStart = startAddress
.max(fHistoryCache[historyIndex].start);
BigInteger minEnd = endAddress
.min(fHistoryCache[historyIndex].end).subtract(
BigInteger.valueOf(1));
BigInteger overlapLength = minEnd
.subtract(maxStart);
if(overlapLength.compareTo(BigInteger.valueOf(0)) > 0)
{
// there is overlap
int offsetIntoOld = maxStart.subtract(
fHistoryCache[historyIndex].start).intValue();
int offsetIntoNew = maxStart.subtract(
startAddress).intValue();
for(int i = overlapLength.intValue(); i >= 0; i--)
{
cachedBytesFinal[offsetIntoNew + i]
.setChanged(historyIndex, cachedBytesFinal[offsetIntoNew
+ i].getValue() != fHistoryCache[historyIndex].bytes[offsetIntoOld
+ i].getValue());
}
}
}
}
fCache = new MemoryUnit();
fCache.start = startAddress;
@ -910,8 +942,8 @@ public class Rendering extends Composite implements IDebugEventSetListener
// If the history does not exist, populate the history with the just populated cache. This solves the
// use case of 1) connect to target; 2) edit memory before the first suspend debug event; 3) paint
// differences in changed color.
if(fHistoryCache == null)
fHistoryCache = fCache.clone();
if(fHistoryCache[0] == null)
fHistoryCache[0] = fCache.clone();
Rendering.this.redrawPanes();
}
@ -927,7 +959,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
}
// bytes will be fetched from cache
public MemoryByte[] getBytes(BigInteger address, int bytesRequested)
public TraditionalMemoryByte[] getBytes(BigInteger address, int bytesRequested)
throws DebugException
{
assert Thread.currentThread().equals(
@ -952,7 +984,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
if(contains)
{
int offset = address.subtract(fCache.start).intValue();
MemoryByte bytes[] = new MemoryByte[bytesRequested];
TraditionalMemoryByte bytes[] = new TraditionalMemoryByte[bytesRequested];
for(int i = 0; i < bytes.length; i++)
{
bytes[i] = fCache.bytes[offset + i];
@ -961,10 +993,10 @@ public class Rendering extends Composite implements IDebugEventSetListener
return bytes;
}
MemoryByte bytes[] = new MemoryByte[bytesRequested];
TraditionalMemoryByte bytes[] = new TraditionalMemoryByte[bytesRequested];
for(int i = 0; i < bytes.length; i++)
{
bytes[i] = new MemoryByte();
bytes[i] = new TraditionalMemoryByte();
bytes[i].setReadable(false);
}
@ -983,13 +1015,13 @@ public class Rendering extends Composite implements IDebugEventSetListener
return fEditBuffer.containsKey(address);
}
private MemoryByte[] getEditedMemory(BigInteger address)
private TraditionalMemoryByte[] getEditedMemory(BigInteger address)
{
assert Thread.currentThread().equals(
Display.getDefault().getThread()) : TraditionalRenderingMessages
.getString("TraditionalRendering.CALLED_ON_NON_DISPATCH_THREAD"); //$NON-NLS-1$
return (MemoryByte[]) fEditBuffer.get(address);
return (TraditionalMemoryByte[]) fEditBuffer.get(address);
}
public void clearEditBuffer()
@ -1014,7 +1046,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
while(iterator.hasNext())
{
BigInteger address = (BigInteger) iterator.next();
MemoryByte[] bytes = (MemoryByte[]) fEditBuffer
TraditionalMemoryByte[] bytes = (TraditionalMemoryByte[]) fEditBuffer
.get(address);
byte byteValue[] = new byte[bytes.length];
@ -1038,7 +1070,7 @@ public class Rendering extends Composite implements IDebugEventSetListener
clearEditBuffer();
}
public void setEditedValue(BigInteger address, MemoryByte[] bytes)
public void setEditedValue(BigInteger address, TraditionalMemoryByte[] bytes)
{
assert Thread.currentThread().equals(
Display.getDefault().getThread()) : TraditionalRenderingMessages

View file

@ -242,7 +242,7 @@ public class TextPane extends AbstractPane
* columns + col)
* fRendering.getAddressesPerColumn()));
MemoryByte bytes[] = fRendering.getBytes(cellAddress,
TraditionalMemoryByte bytes[] = fRendering.getBytes(cellAddress,
fRendering.getBytesPerColumn());
if(fRendering.getSelection().isSelected(cellAddress))
@ -281,31 +281,46 @@ public class TextPane extends AbstractPane
}
protected void applyCustomColor(GC gc, MemoryByte bytes[], int col)
{
// TODO reuse, this could be in the abstract base
// TODO consider adding finer granularity?
boolean anyByteChanged = false;
for(int n = 0; n < bytes.length && !anyByteChanged; n++)
if(bytes[n].isChanged())
anyByteChanged = true;
// TODO consider adding finer granularity?
// Allow subclasses to override this method to do their own coloring
protected void applyCustomColor(GC gc, TraditionalMemoryByte bytes[], int col)
{
// TODO consider adding finer granularity?
boolean anyByteEditing = false;
for(int n = 0; n < bytes.length && !anyByteEditing; n++)
if(bytes[n] instanceof TraditionalMemoryByte)
if(((TraditionalMemoryByte) bytes[n]).isEdited())
anyByteEditing = true;
if(anyByteEditing)
gc.setForeground(fRendering.getTraditionalRendering().getColorEdit());
else if(anyByteChanged)
gc.setForeground(fRendering.getTraditionalRendering().getColorChanged());
else if(isOdd(col))
gc.setForeground(fRendering.getTraditionalRendering().getColorText());
else
gc.setForeground(fRendering.getTraditionalRendering().getColorTextAlternate());
gc.setBackground(fRendering.getTraditionalRendering().getColorBackground());
}
if(((TraditionalMemoryByte) bytes[n]).isEdited())
anyByteEditing = true;
if(isOdd(col))
gc.setForeground(fRendering.getTraditionalRendering().getColorText());
else
gc.setForeground(fRendering.getTraditionalRendering().getColorTextAlternate());
gc.setBackground(fRendering.getTraditionalRendering().getColorBackground());
if(anyByteEditing)
{
gc.setForeground(fRendering.getTraditionalRendering().getColorEdit());
}
else
{
boolean isColored = false;
for(int i = 0; i < fRendering.getHistoryDepth() && !isColored; i++)
{
// TODO consider adding finer granularity?
for(int n = 0; n < bytes.length; n++)
{
if(bytes[n].isChanged(i))
{
if(i == 0)
gc.setForeground(fRendering.getTraditionalRendering().getColorsChanged()[i]);
else
gc.setBackground(fRendering.getTraditionalRendering().getColorsChanged()[i]);
isColored = true;
break;
}
}
}
}
}
}

View file

@ -352,6 +352,7 @@ public class TraditionalRendering extends AbstractMemoryRendering implements IRe
private Color colorBackground;
private Color colorChanged;
private Color colorsChanged[] = null;
private Color colorEdit;
private Color colorSelection;
private Color colorText;
@ -417,12 +418,18 @@ public class TraditionalRendering extends AbstractMemoryRendering implements IRe
if(colorTextAlternate != null)
colorTextAlternate.dispose();
colorTextAlternate = null;
disposeChangedColors();
}
public void applyPreferences()
{
if(!fRendering.isDisposed())
{
IPreferenceStore store = TraditionalRenderingPlugin.getDefault().getPreferenceStore();
fRendering.setHistoryDepth(store.getInt(TraditionalRenderingPreferenceConstants.MEM_HISTORY_TRAILS_COUNT));
fRendering.setBackground(getColorBackground());
AbstractPane panes[] = fRendering.getRenderingPanes();
@ -448,6 +455,41 @@ public class TraditionalRendering extends AbstractMemoryRendering implements IRe
return colorChanged;
}
private void disposeChangedColors()
{
if(colorsChanged != null)
for(int i = 0; i < colorsChanged.length; i++)
colorsChanged[i].dispose();
colorsChanged = null;
}
public Color[] getColorsChanged()
{
if(colorsChanged != null && colorsChanged.length != fRendering.getHistoryDepth())
{
disposeChangedColors();
}
if(colorsChanged == null)
{
colorsChanged = new Color[fRendering.getHistoryDepth()];
colorsChanged[0] = colorChanged;
int shades = fRendering.getHistoryDepth() + 4;
int red = (255 - colorChanged.getRed()) / shades;
int green = (255 - colorChanged.getGreen()) / shades;
int blue = (255 - colorChanged.getBlue()) / shades;
for(int i = 1; i < fRendering.getHistoryDepth(); i++)
{
colorsChanged[i] = new Color(colorChanged.getDevice(),
colorChanged.getRed() + ((shades - i) * red),
colorChanged.getGreen() + ((shades - i) * green),
colorChanged.getBlue() + ((shades - i) * blue));
}
}
return colorsChanged;
}
public Color getColorEdit()
{
return colorEdit;
@ -1060,6 +1102,7 @@ public class TraditionalRendering extends AbstractMemoryRendering implements IRe
{
if(this.fRendering != null)
this.fRendering.dispose();
disposeColors();
super.dispose();
}
@ -1126,11 +1169,23 @@ class TraditionalMemoryByte extends MemoryByte implements IMemoryByte
{
private boolean isEdited = false;
private boolean[] changeHistory = new boolean[0];
public TraditionalMemoryByte()
{
super();
}
public TraditionalMemoryByte(byte byteValue)
{
super(byteValue);
}
public TraditionalMemoryByte(byte byteValue, byte byteFlags)
{
super(byteValue, byteFlags);
}
public boolean isEdited()
{
return isEdited;
@ -1140,6 +1195,26 @@ class TraditionalMemoryByte extends MemoryByte implements IMemoryByte
{
isEdited = edited;
}
public boolean isChanged(int historyDepth)
{
return changeHistory.length > historyDepth && changeHistory[historyDepth];
}
public void setChanged(int historyDepth, boolean changed)
{
if(historyDepth >= changeHistory.length)
{
boolean newChangeHistory[] = new boolean[historyDepth + 1];
System.arraycopy(changeHistory, 0, newChangeHistory, 0, changeHistory.length);
changeHistory = newChangeHistory;
}
changeHistory[historyDepth] = changed;
if(historyDepth == 0)
this.setChanged(changed);
}
}
class CopyAction extends Action

View file

@ -40,4 +40,6 @@ public class TraditionalRenderingPreferenceConstants {
public static final String MEM_EDIT_BUFFER_SAVE_ON_ENTER_OR_FOCUS_LOST = "saveOnEnterOrFocusLost";
public static final String MEM_HISTORY_TRAILS_COUNT = "memoryHistoryTrailsCount";
}

View file

@ -56,6 +56,8 @@ public class TraditionalRenderingPreferenceInitializer extends AbstractPreferenc
store.setDefault(TraditionalRenderingPreferenceConstants.MEM_EDIT_BUFFER_SAVE,
TraditionalRenderingPreferenceConstants.MEM_EDIT_BUFFER_SAVE_ON_ENTER_ONLY);
store.setDefault(TraditionalRenderingPreferenceConstants.MEM_HISTORY_TRAILS_COUNT, "1");
}
}

View file

@ -80,6 +80,9 @@ public class TraditionalRenderingPreferencePage
addField(new RadioGroupFieldEditor(TraditionalRenderingPreferenceConstants.MEM_EDIT_BUFFER_SAVE,
"Edit Buffer", 1, new String[][] { { "Save on E&nter, Cancel on Focus Lost", "saveOnEnterCancelOnFocusLost" },
{ "Save on Enter or Focus L&ost", "saveOnEnterOrFocusLost" } }, getFieldEditorParent()));
addField(new ScaleFieldEditor(TraditionalRenderingPreferenceConstants.MEM_HISTORY_TRAILS_COUNT,
"History &Trail Levels", getFieldEditorParent(), 1, 10, 1, 1));
}
/* (non-Javadoc)