diff options
author | Eugene Tarassov | 2015-08-19 22:58:12 +0000 |
---|---|---|
committer | Eugene Tarassov | 2015-08-19 22:58:12 +0000 |
commit | 1c6bd1396e529492d84fd40ea4a9292a894e3c1b (patch) | |
tree | 14405ef45b338d99910f084564657ab0574c02cd /plugins | |
parent | 3b1f240e0fbaf2e60e0efc998c084f53ac90de2e (diff) | |
download | org.eclipse.tcf-1c6bd1396e529492d84fd40ea4a9292a894e3c1b.tar.gz org.eclipse.tcf-1c6bd1396e529492d84fd40ea4a9292a894e3c1b.tar.xz org.eclipse.tcf-1c6bd1396e529492d84fd40ea4a9292a894e3c1b.zip |
TCF Debugger: fixed: memory monitors disappear if a context exits and then re-created.
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/org.eclipse.tcf.debug.ui/plugin.xml | 2 | ||||
-rw-r--r-- | plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFMemoryBlock.java (renamed from plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFMemoryBlockRetrieval.java) | 990 | ||||
-rw-r--r-- | plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java | 168 | ||||
-rw-r--r-- | plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModelManager.java | 2 | ||||
-rw-r--r-- | plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java | 2 |
5 files changed, 588 insertions, 576 deletions
diff --git a/plugins/org.eclipse.tcf.debug.ui/plugin.xml b/plugins/org.eclipse.tcf.debug.ui/plugin.xml index 0894ffbf2..766d4a2e8 100644 --- a/plugins/org.eclipse.tcf.debug.ui/plugin.xml +++ b/plugins/org.eclipse.tcf.debug.ui/plugin.xml @@ -752,7 +752,7 @@ primaryId="org.eclipse.debug.ui.rendering.hexint" renderingIds="org.eclipse.debug.ui.rendering.hexint,org.eclipse.debug.ui.rendering.signedint,org.eclipse.debug.ui.rendering.unsignedint,org.eclipse.debug.ui.rendering.ascii,org.eclipse.debug.ui.rendering.raw_memory"> <enablement> - <instanceof value="org.eclipse.tcf.internal.debug.ui.model.TCFMemoryBlockRetrieval$MemoryBlock"/> + <instanceof value="org.eclipse.tcf.internal.debug.ui.model.TCFMemoryBlock"/> </enablement> </renderingBindings> </extension> diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFMemoryBlockRetrieval.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFMemoryBlock.java index ae950a886..860aa42f2 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFMemoryBlockRetrieval.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFMemoryBlock.java @@ -81,16 +81,13 @@ import org.w3c.dom.Node; import org.xml.sax.helpers.DefaultHandler; /** - * A memory block retrieval allows the user interface to request a memory block from a debugger when needed. - * TCF memory block retrieval is based on TCF Memory service. + * A memory block allows the user interface to request a memory block data from the debugger when needed. + * TCF memory block is based on TCF Memory service. */ -class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { - - private final TCFNodeExecContext exec_ctx; - private final HashSet<MemoryBlock> mem_blocks = new HashSet<MemoryBlock>(); - private final LinkedList<ModelProxy> model_proxies = new LinkedList<ModelProxy>(); +class TCFMemoryBlock extends PlatformObject implements IMemoryBlockExtension, IModelProxyFactory { private static class MemData { + final BigInteger addr; final MemoryByte[] data; final byte[] bytes; @@ -104,589 +101,548 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { } } - private class MemoryBlock extends PlatformObject implements IMemoryBlockExtension, IModelProxyFactory { + private static class ModelProxy extends AbstractModelProxy implements Runnable { - private final String ctx_id; - private final String expression; - private final long length; - private final Set<Object> connections = new HashSet<Object>(); - private final TCFDataCache<IExpressions.Expression> remote_expression; - private final TCFDataCache<IExpressions.Value> expression_value; + final TCFMemoryBlock mem_block; + final Display display; - private boolean disposed; + ModelDelta delta; - private MemData mem_data; // current memory block data - private MemData mem_prev; // previous data - before last suspend - private MemData mem_last; // last retrieved memory block data + public ModelProxy(TCFMemoryBlock mem_block, Display display) { + this.mem_block = mem_block; + this.display = display; + } - MemoryBlock(final String expression, long length) { - this.ctx_id = exec_ctx.id; - this.expression = expression; - this.length = length; - mem_blocks.add(this); - final TCFLaunch launch = exec_ctx.model.getLaunch(); - final IChannel channel = launch.getChannel(); - remote_expression = new TCFDataCache<IExpressions.Expression>(channel) { - @Override - protected boolean startDataRetrieval() { - IExpressions exps = launch.getService(IExpressions.class); - if (exps == null) { - set(null, new Exception("Expressions service not available"), null); - return true; - } - command = exps.create(ctx_id, null, expression, new IExpressions.DoneCreate() { - @Override - public void doneCreate(IToken token, Exception error, IExpressions.Expression context) { - if (disposed) { - if (context != null) { - IExpressions exps = channel.getRemoteService(IExpressions.class); - exps.dispose(context.getID(), new IExpressions.DoneDispose() { - @Override - public void doneDispose(IToken token, Exception error) { - if (error == null) return; - if (channel.getState() != IChannel.STATE_OPEN) return; - Activator.log("Error disposing remote expression evaluator", error); - } - }); - } - return; - } - set(token, error, context); - } - }); - return false; - } - }; - expression_value = new TCFDataCache<IExpressions.Value>(channel) { - @Override - protected boolean startDataRetrieval() { - if (!remote_expression.validate(this)) return false; - final IExpressions.Expression ctx = remote_expression.getData(); - if (ctx == null) { - set(null, null, null); - return true; - } - IExpressions exps = launch.getService(IExpressions.class); - command = exps.evaluate(ctx.getID(), new IExpressions.DoneEvaluate() { - @Override - public void doneEvaluate(IToken token, Exception error, IExpressions.Value value) { - set(token, error, value); - } - }); - return false; - } - }; + @Override + public void installed(Viewer viewer) { + synchronized (mem_block.model_proxies) { + if (isDisposed()) return; + setInstalled(true); + super.installed(viewer); + mem_block.model_proxies.add(this); + } + } + + @Override + public void dispose() { + synchronized (mem_block.model_proxies) { + if (isDisposed()) return; + mem_block.model_proxies.remove(this); + super.dispose(); + } } - private void close() { + void onMemoryChanged(boolean suspended) { assert Protocol.isDispatchThread(); - assert !disposed; - disposed = true; - expression_value.dispose(); - if (remote_expression.isValid() && remote_expression.getData() != null) { - final IChannel channel = exec_ctx.channel; - if (channel.getState() == IChannel.STATE_OPEN) { - IExpressions exps = channel.getRemoteService(IExpressions.class); - exps.dispose(remote_expression.getData().getID(), new IExpressions.DoneDispose() { + int flags = IModelDelta.CONTENT; + if (suspended) flags |= IModelDelta.STATE; + if (delta != null) { + delta.setFlags(delta.getFlags() | flags); + } + else { + delta = new ModelDelta(mem_block, flags); + Protocol.invokeLater(this); + } + } + + @Override + public void run() { + // Note: double posting is necessary to avoid deadlocks + assert Protocol.isDispatchThread(); + final ModelDelta d = delta; + delta = null; + synchronized (Device.class) { + if (!display.isDisposed()) { + display.asyncExec(new Runnable() { @Override - public void doneDispose(IToken token, Exception error) { - if (error == null) return; - if (channel.getState() != IChannel.STATE_OPEN) return; - Activator.log("Error disposing remote expression evaluator", error); + public void run() { + fireModelChanged(d); } }); } } - remote_expression.dispose(); - mem_blocks.remove(MemoryBlock.this); } + } - @Override - public synchronized void connect(Object client) { - connections.add(client); - } + private final TCFModel model; + private final IMemoryBlockRetrieval block_retrieval; + private final String ctx_id; + private final String expression; + private final long length; + private final Set<Object> connections = new HashSet<Object>(); + private final TCFDataCache<IExpressions.Expression> remote_expression; + private final TCFDataCache<IExpressions.Value> expression_value; + private final LinkedList<ModelProxy> model_proxies = new LinkedList<ModelProxy>(); - @Override - public synchronized void disconnect(Object client) { - connections.remove(client); - } + private MemData mem_data; // current memory block data + private MemData mem_prev; // previous data - before last suspend + private MemData mem_last; // last retrieved memory block data - @Override - public synchronized Object[] getConnections() { - return connections.toArray(new Object[connections.size()]); - } + private boolean disposed; - @Override - public void dispose() throws DebugException { - if (disposed) return; - new TCFDebugTask<Boolean>(exec_ctx.getChannel()) { - @Override - public void run() { - if (!disposed) close(); - done(Boolean.TRUE); + TCFMemoryBlock(final TCFModel model, IMemoryBlockRetrieval block_retrieval, final String ctx_id, final String expression, long length) { + assert Protocol.isDispatchThread(); + this.model = model; + this.block_retrieval = block_retrieval; + this.ctx_id = ctx_id; + this.expression = expression; + this.length = length; + final TCFLaunch launch = model.getLaunch(); + final IChannel channel = launch.getChannel(); + remote_expression = new TCFDataCache<IExpressions.Expression>(channel) { + @Override + protected boolean startDataRetrieval() { + IExpressions exps = launch.getService(IExpressions.class); + if (exps == null) { + set(null, new Exception("Expressions service not available"), null); + return true; } - }.getD(); - } + command = exps.create(ctx_id, null, expression, new IExpressions.DoneCreate() { + @Override + public void doneCreate(IToken token, Exception error, IExpressions.Expression context) { + TCFNode node = model.getNode(ctx_id); + if (node == null) { + if (context != null) { + IExpressions exps = channel.getRemoteService(IExpressions.class); + exps.dispose(context.getID(), new IExpressions.DoneDispose() { + @Override + public void doneDispose(IToken token, Exception error) { + if (error == null) return; + if (channel.getState() != IChannel.STATE_OPEN) return; + Activator.log("Error disposing remote expression evaluator", error); + } + }); + } + return; + } + set(token, error, context); + } + }); + return false; + } + }; + expression_value = new TCFDataCache<IExpressions.Value>(channel) { + @Override + protected boolean startDataRetrieval() { + if (!remote_expression.validate(this)) return false; + final IExpressions.Expression ctx = remote_expression.getData(); + if (ctx == null) { + set(null, null, null); + return true; + } + IExpressions exps = launch.getService(IExpressions.class); + command = exps.evaluate(ctx.getID(), new IExpressions.DoneEvaluate() { + @Override + public void doneEvaluate(IToken token, Exception error, IExpressions.Value value) { + set(token, error, value); + } + }); + return false; + } + }; + } - @Override - public int getAddressSize() throws DebugException { - return new TCFDebugTask<Integer>(exec_ctx.getChannel()) { - @Override - public void run() { - if (exec_ctx.isDisposed()) { - error("Context is disposed"); + @Override + public synchronized void connect(Object client) { + connections.add(client); + } + + @Override + public synchronized void disconnect(Object client) { + connections.remove(client); + } + + @Override + public synchronized Object[] getConnections() { + return connections.toArray(new Object[connections.size()]); + } + + @Override + public void dispose() throws DebugException { + if (disposed) return; + new TCFDebugTask<Boolean>() { + @Override + public void run() { + if (!disposed) { + onContextExited(ctx_id); + expression_value.dispose(); + remote_expression.dispose(); + disposed = true; + } + done(Boolean.TRUE); + } + }.getD(); + } + + @Override + public int getAddressSize() throws DebugException { + return new TCFDebugTask<Integer>(model.getChannel()) { + @Override + public void run() { + TCFNode node = model.getNode(ctx_id); + if (node == null) { + error("Context is disposed"); + } + else if (node instanceof TCFNodeExecContext) { + TCFDataCache<IMemory.MemoryContext> cache = ((TCFNodeExecContext)node).getMemoryContext(); + if (!cache.validate(this)) return; + if (cache.getError() != null) { + error(cache.getError()); } else { - TCFDataCache<IMemory.MemoryContext> cache = exec_ctx.getMemoryContext(); - if (!cache.validate(this)) return; - if (cache.getError() != null) { - error(cache.getError()); + IMemory.MemoryContext mem = cache.getData(); + if (mem == null) { + error("Context does not provide memory access"); } else { - IMemory.MemoryContext mem = cache.getData(); - if (mem == null) { - error("Context does not provide memory access"); - } - else { - done(mem.getAddressSize()); - } + done(mem.getAddressSize()); } } } - }.getD(); - } + else { + error("Context does not provide memory access"); + } + } + }.getD(); + } - @Override - public int getAddressableSize() throws DebugException { - return new TCFDebugTask<Integer>(exec_ctx.getChannel()) { - @Override - public void run() { - if (exec_ctx.isDisposed()) { - error("Context is disposed"); + @Override + public int getAddressableSize() throws DebugException { + return new TCFDebugTask<Integer>(model.getChannel()) { + @Override + public void run() { + TCFNode node = model.getNode(ctx_id); + if (node == null) { + error("Context is disposed"); + } + else if (node instanceof TCFNodeExecContext) { + TCFDataCache<IMemory.MemoryContext> cache = ((TCFNodeExecContext)node).getMemoryContext(); + if (!cache.validate(this)) return; + if (cache.getError() != null) { + error(cache.getError()); } else { - TCFDataCache<IMemory.MemoryContext> cache = exec_ctx.getMemoryContext(); - if (!cache.validate(this)) return; - if (cache.getError() != null) { - error(cache.getError()); + IMemory.MemoryContext mem = cache.getData(); + if (mem == null) { + error("Context does not provide memory access"); } else { - IMemory.MemoryContext mem = cache.getData(); - if (mem == null) { - error("Context does not provide memory access"); - } - else { - done(mem.getAddressableUnitSize()); - } + done(mem.getAddressableUnitSize()); } } } - }.getD(); - } + else { + error("Context does not provide memory access"); + } + } + }.getD(); + } - @Override - public BigInteger getBigBaseAddress() throws DebugException { - return new TCFDebugTask<BigInteger>(exec_ctx.getChannel()) { - @Override - public void run() { - if (!expression_value.validate()) { - expression_value.wait(this); - } - else if (expression_value.getError() != null) { - error(expression_value.getError()); - } - else if (expression_value.getData() == null) { - error("Address expression evaluation failed"); + @Override + public BigInteger getBigBaseAddress() throws DebugException { + return new TCFDebugTask<BigInteger>(model.getChannel()) { + @Override + public void run() { + if (!expression_value.validate()) { + expression_value.wait(this); + } + else if (expression_value.getError() != null) { + error(expression_value.getError()); + } + else if (expression_value.getData() == null) { + error("Address expression evaluation failed"); + } + else { + IExpressions.Value value = expression_value.getData(); + if (value.getTypeClass() == ISymbols.TypeClass.array) { + BigInteger addr = JSON.toBigInteger(value.getAddress()); + if (addr == null) { + error("Invalid expression: array without memory address"); + } + else { + done(addr); + } } else { - IExpressions.Value value = expression_value.getData(); - if (value.getTypeClass() == ISymbols.TypeClass.array) { - BigInteger addr = JSON.toBigInteger(value.getAddress()); - if (addr == null) { - error("Invalid expression: array without memory address"); - } - else { - done(addr); - } + byte[] data = value.getValue(); + if (data == null || data.length == 0) { + error("Address expression value is empty (void)"); } else { - byte[] data = value.getValue(); - if (data == null || data.length == 0) { - error("Address expression value is empty (void)"); - } - else { - boolean signed = value.getTypeClass() == ISymbols.TypeClass.integer; - done(TCFNumberFormat.toBigInteger(data, value.isBigEndian(), signed)); - } + boolean signed = value.getTypeClass() == ISymbols.TypeClass.integer; + done(TCFNumberFormat.toBigInteger(data, value.isBigEndian(), signed)); } } } - }.getD(); - } + } + }.getD(); + } - @Override - public MemoryByte[] getBytesFromAddress(final BigInteger address, final long units) throws DebugException { - return new TCFDebugTask<MemoryByte[]>(exec_ctx.getChannel()) { - int offs = 0; - @Override - public void run() { - if (mem_data != null && - address.compareTo(mem_data.addr) >= 0 && - address.add(BigInteger.valueOf(units)).compareTo( - mem_data.addr.add(BigInteger.valueOf(mem_data.data.length))) <= 0) { - offs = address.subtract(mem_data.addr).intValue(); - MemoryByte[] res = mem_data.data; - if (units < mem_data.data.length) { - res = new MemoryByte[(int)units]; - System.arraycopy(mem_data.data, offs, res, 0, res.length); - } - setHistoryFlags(); - done(res); - return; - } - if (exec_ctx.isDisposed()) { - error("Context is disposed"); - return; - } - TCFDataCache<IMemory.MemoryContext> cache = exec_ctx.getMemoryContext(); - if (!cache.validate(this)) return; - if (cache.getError() != null) { - error(cache.getError()); - return; - } - final IMemory.MemoryContext mem = cache.getData(); - if (mem == null) { - error("Context does not provide memory access"); - return; + @Override + public MemoryByte[] getBytesFromAddress(final BigInteger address, final long units) throws DebugException { + return new TCFDebugTask<MemoryByte[]>(model.getChannel()) { + int offs = 0; + @Override + public void run() { + if (mem_data != null && + address.compareTo(mem_data.addr) >= 0 && + address.add(BigInteger.valueOf(units)).compareTo( + mem_data.addr.add(BigInteger.valueOf(mem_data.data.length))) <= 0) { + offs = address.subtract(mem_data.addr).intValue(); + MemoryByte[] res = mem_data.data; + if (units < mem_data.data.length) { + res = new MemoryByte[(int)units]; + System.arraycopy(mem_data.data, offs, res, 0, res.length); } - final int size = (int)units; - final int mode = IMemory.MODE_CONTINUEONERROR | IMemory.MODE_VERIFY; - final byte[] buf = new byte[size]; - final MemoryByte[] res = new MemoryByte[size]; - mem.get(address, 1, buf, 0, size, mode, new IMemory.DoneMemory() { - @Override - public void doneMemory(IToken token, MemoryError error) { - int big_endian = 0; - if (mem.getProperties().get(IMemory.PROP_BIG_ENDIAN) != null) { - big_endian |= MemoryByte.ENDIANESS_KNOWN; - if (mem.isBigEndian()) big_endian |= MemoryByte.BIG_ENDIAN; - } - int cnt = 0; - while (offs < size) { - int flags = big_endian; - if (error instanceof IMemory.ErrorOffset) { - IMemory.ErrorOffset ofs = (IMemory.ErrorOffset)error; - int status = ofs.getStatus(cnt); - if (status == IMemory.ErrorOffset.BYTE_VALID) { - flags |= MemoryByte.READABLE | MemoryByte.WRITABLE; - } - else if ((status & IMemory.ErrorOffset.BYTE_UNKNOWN) != 0) { - if (cnt > 0) break; - } - } - else if (error == null) { + setHistoryFlags(); + done(res); + return; + } + TCFNode node = model.getNode(ctx_id); + if (node == null) { + error("Context is disposed"); + return; + } + if (!(node instanceof TCFNodeExecContext)) { + error("Context does not provide memory access"); + return; + } + TCFDataCache<IMemory.MemoryContext> cache = ((TCFNodeExecContext)node).getMemoryContext(); + if (!cache.validate(this)) return; + if (cache.getError() != null) { + error(cache.getError()); + return; + } + final IMemory.MemoryContext mem = cache.getData(); + if (mem == null) { + error("Context does not provide memory access"); + return; + } + final int size = (int)units; + final int mode = IMemory.MODE_CONTINUEONERROR | IMemory.MODE_VERIFY; + final byte[] buf = new byte[size]; + final MemoryByte[] res = new MemoryByte[size]; + mem.get(address, 1, buf, 0, size, mode, new IMemory.DoneMemory() { + @Override + public void doneMemory(IToken token, MemoryError error) { + int big_endian = 0; + if (mem.getProperties().get(IMemory.PROP_BIG_ENDIAN) != null) { + big_endian |= MemoryByte.ENDIANESS_KNOWN; + if (mem.isBigEndian()) big_endian |= MemoryByte.BIG_ENDIAN; + } + int cnt = 0; + while (offs < size) { + int flags = big_endian; + if (error instanceof IMemory.ErrorOffset) { + IMemory.ErrorOffset ofs = (IMemory.ErrorOffset)error; + int status = ofs.getStatus(cnt); + if (status == IMemory.ErrorOffset.BYTE_VALID) { flags |= MemoryByte.READABLE | MemoryByte.WRITABLE; } - res[offs] = new MemoryByte(buf[offs], (byte)flags); - offs++; - cnt++; - } - if (offs < size) { - mem.get(address.add(BigInteger.valueOf(offs)), 1, buf, offs, size - offs, mode, this); + else if ((status & IMemory.ErrorOffset.BYTE_UNKNOWN) != 0) { + if (cnt > 0) break; + } } - else { - mem_last = mem_data = new MemData(address, res); - setHistoryFlags(); - done(res); + else if (error == null) { + flags |= MemoryByte.READABLE | MemoryByte.WRITABLE; } + res[offs] = new MemoryByte(buf[offs], (byte)flags); + offs++; + cnt++; + } + if (offs < size) { + mem.get(address.add(BigInteger.valueOf(offs)), 1, buf, offs, size - offs, mode, this); + } + else { + mem_last = mem_data = new MemData(address, res); + setHistoryFlags(); + done(res); } - }); - } - }.getD(); - } - - private void setHistoryFlags() { - if (mem_data == null) return; - BigInteger addr = mem_data.addr; - BigInteger his_start = null; - BigInteger his_end = null; - if (mem_prev != null) { - his_start = mem_prev.addr; - his_end = mem_prev.addr.add(BigInteger.valueOf(mem_prev.data.length)); - } - for (MemoryByte b : mem_data.data) { - int flags = b.getFlags(); - if (mem_prev != null && addr.compareTo(his_start) >= 0 && addr.compareTo(his_end) < 0) { - flags |= MemoryByte.HISTORY_KNOWN; - int offs = addr.subtract(his_start).intValue(); - if (b.getValue() != mem_prev.data[offs].getValue()) { - flags |= MemoryByte.CHANGED; } - } - else { - flags &= ~(MemoryByte.HISTORY_KNOWN | MemoryByte.CHANGED); - } - b.setFlags((byte)flags); - addr = addr.add(BigInteger.valueOf(1)); + }); } - } - - @Override - public MemoryByte[] getBytesFromOffset(BigInteger offset, long units) throws DebugException { - return getBytesFromAddress(getBigBaseAddress().add(offset), units); - } - - @Override - public String getExpression() { - return expression; - } - - @Override - public IMemoryBlockRetrieval getMemoryBlockRetrieval() { - return TCFMemoryBlockRetrieval.this; - } - - @Override - public long getStartAddress() { - return 0; // Unbounded - } - - @Override - public long getLength() { - return length; - } - - @Override - public BigInteger getMemoryBlockStartAddress() throws DebugException { - return null; // Unbounded - } - - @Override - public BigInteger getMemoryBlockEndAddress() throws DebugException { - return null; // Unbounded - } - - @Override - public BigInteger getBigLength() throws DebugException { - return BigInteger.valueOf(length); - } - - @Override - public void setBaseAddress(BigInteger address) throws DebugException { - } + }.getD(); + } - @Override - public void setValue(BigInteger offset, final byte[] bytes) throws DebugException { - final BigInteger address = getBigBaseAddress().add(offset); - new TCFDebugTask<Object>(exec_ctx.getChannel()) { - @Override - public void run() { - if (exec_ctx.isDisposed()) { - error("Context is disposed"); - return; - } - TCFDataCache<IMemory.MemoryContext> cache = exec_ctx.getMemoryContext(); - if (!cache.validate(this)) return; - if (cache.getError() != null) { - error(cache.getError()); - return; - } - final IMemory.MemoryContext mem = cache.getData(); - if (mem == null) { - error("Context does not provide memory access"); - return; - } - final int mode = IMemory.MODE_CONTINUEONERROR | IMemory.MODE_VERIFY; - mem.set(address, 1, bytes, 0, bytes.length, mode, new IMemory.DoneMemory() { - @Override - public void doneMemory(IToken token, MemoryError error) { - if (error != null) { - error(error); - } - else { - done(null); - } - } - }); + private void setHistoryFlags() { + if (mem_data == null) return; + BigInteger addr = mem_data.addr; + BigInteger his_start = null; + BigInteger his_end = null; + if (mem_prev != null) { + his_start = mem_prev.addr; + his_end = mem_prev.addr.add(BigInteger.valueOf(mem_prev.data.length)); + } + for (MemoryByte b : mem_data.data) { + int flags = b.getFlags(); + if (mem_prev != null && addr.compareTo(his_start) >= 0 && addr.compareTo(his_end) < 0) { + flags |= MemoryByte.HISTORY_KNOWN; + int offs = addr.subtract(his_start).intValue(); + if (b.getValue() != mem_prev.data[offs].getValue()) { + flags |= MemoryByte.CHANGED; } - }.getD(); - } - - @Override - public boolean supportBaseAddressModification() throws DebugException { - return false; - } - - @Override - public boolean supportsChangeManagement() { - return true; + } + else { + flags &= ~(MemoryByte.HISTORY_KNOWN | MemoryByte.CHANGED); + } + b.setFlags((byte)flags); + addr = addr.add(BigInteger.valueOf(1)); } + } - @Override - public byte[] getBytes() throws DebugException { - if (mem_data == null) return null; - return mem_data.bytes; - } + @Override + public MemoryByte[] getBytesFromOffset(BigInteger offset, long units) throws DebugException { + return getBytesFromAddress(getBigBaseAddress().add(offset), units); + } - @Override - public void setValue(long offset, byte[] bytes) throws DebugException { - setValue(BigInteger.valueOf(offset), bytes); - } + @Override + public String getExpression() { + return expression; + } - @Override - public boolean supportsValueModification() { - return true; - } + @Override + public IMemoryBlockRetrieval getMemoryBlockRetrieval() { + return block_retrieval; + } - @Override - public IDebugTarget getDebugTarget() { - return null; - } + @Override + public long getStartAddress() { + return 0; // Unbounded + } - @Override - public ILaunch getLaunch() { - return exec_ctx.model.getLaunch(); - } + @Override + public long getLength() { + return length; + } - @Override - public String getModelIdentifier() { - return ITCFConstants.ID_TCF_DEBUG_MODEL; - } + @Override + public BigInteger getMemoryBlockStartAddress() throws DebugException { + return null; // Unbounded + } - @Override - public IModelProxy createModelProxy(Object element, IPresentationContext context) { - assert element == this; - return new ModelProxy(this, context.getWindow().getShell().getDisplay()); - } + @Override + public BigInteger getMemoryBlockEndAddress() throws DebugException { + return null; // Unbounded + } - @Override - @SuppressWarnings("rawtypes") - public Object getAdapter(Class adapter) { - if (adapter == IMemoryBlockRetrieval.class) return TCFMemoryBlockRetrieval.this; - if (adapter == IMemoryBlockRetrievalExtension.class) return TCFMemoryBlockRetrieval.this; - return super.getAdapter(adapter); - } + @Override + public BigInteger getBigLength() throws DebugException { + return BigInteger.valueOf(length); } - private class ModelProxy extends AbstractModelProxy implements Runnable { + @Override + public void setBaseAddress(BigInteger address) throws DebugException { + } - final MemoryBlock mem_block; - final Display display; + @Override + public void setValue(BigInteger offset, final byte[] bytes) throws DebugException { + final BigInteger address = getBigBaseAddress().add(offset); + new TCFDebugTask<Object>(model.getChannel()) { + @Override + public void run() { + TCFNode node = model.getNode(ctx_id); + if (node == null) { + error("Context is disposed"); + return; + } + if (!(node instanceof TCFNodeExecContext)) { + error("Context does not provide memory access"); + return; + } + TCFDataCache<IMemory.MemoryContext> cache = ((TCFNodeExecContext)node).getMemoryContext(); + if (!cache.validate(this)) return; + if (cache.getError() != null) { + error(cache.getError()); + return; + } + final IMemory.MemoryContext mem = cache.getData(); + if (mem == null) { + error("Context does not provide memory access"); + return; + } + final int mode = IMemory.MODE_CONTINUEONERROR | IMemory.MODE_VERIFY; + mem.set(address, 1, bytes, 0, bytes.length, mode, new IMemory.DoneMemory() { + @Override + public void doneMemory(IToken token, MemoryError error) { + if (error != null) { + error(error); + } + else { + done(null); + } + } + }); + } + }.getD(); + } - ModelDelta delta; + @Override + public boolean supportBaseAddressModification() throws DebugException { + return false; + } - public ModelProxy(MemoryBlock mem_block, Display display) { - this.mem_block = mem_block; - this.display = display; - } + @Override + public boolean supportsChangeManagement() { + return true; + } - @Override - public void installed(Viewer viewer) { - synchronized (model_proxies) { - if (isDisposed()) return; - setInstalled(true); - super.installed(viewer); - model_proxies.add(this); - } - } + @Override + public byte[] getBytes() throws DebugException { + if (mem_data == null) return null; + return mem_data.bytes; + } - @Override - public void dispose() { - synchronized (model_proxies) { - if (isDisposed()) return; - model_proxies.remove(this); - super.dispose(); - } - } + @Override + public void setValue(long offset, byte[] bytes) throws DebugException { + setValue(BigInteger.valueOf(offset), bytes); + } - void onMemoryChanged(boolean suspended) { - assert Protocol.isDispatchThread(); - int flags = IModelDelta.CONTENT; - if (suspended) flags |= IModelDelta.STATE; - if (delta != null) { - delta.setFlags(delta.getFlags() | flags); - } - else { - delta = new ModelDelta(mem_block, flags); - Protocol.invokeLater(this); - } - } + @Override + public boolean supportsValueModification() { + return true; + } - @Override - public void run() { - // Note: double posting is necessary to avoid deadlocks - assert Protocol.isDispatchThread(); - final ModelDelta d = delta; - delta = null; - synchronized (Device.class) { - if (!display.isDisposed()) { - display.asyncExec(new Runnable() { - @Override - public void run() { - fireModelChanged(d); - } - }); - } - } - } + @Override + public IDebugTarget getDebugTarget() { + return null; } - TCFMemoryBlockRetrieval(TCFNodeExecContext exec_ctx) { - this.exec_ctx = exec_ctx; + @Override + public ILaunch getLaunch() { + return model.getLaunch(); } @Override - public IMemoryBlockExtension getExtendedMemoryBlock(final String expression, Object context) throws DebugException { - return new TCFDebugTask<IMemoryBlockExtension>() { - @Override - public void run() { - if (!exec_ctx.getMemoryContext().validate(this)) return; - if (exec_ctx.getMemoryContext().getError() != null) { - error(exec_ctx.getMemoryContext().getError()); - } - else { - done(new MemoryBlock(expression, -1)); - } - } - }.getD(); + public String getModelIdentifier() { + return ITCFConstants.ID_TCF_DEBUG_MODEL; } @Override - public IMemoryBlock getMemoryBlock(final long address, final long length) throws DebugException { - return new TCFDebugTask<IMemoryBlockExtension>() { - @Override - public void run() { - if (!exec_ctx.getMemoryContext().validate(this)) return; - if (exec_ctx.getMemoryContext().getError() != null) { - error(exec_ctx.getMemoryContext().getError()); - } - else { - done(new MemoryBlock("0x" + Long.toHexString(address), length)); - } - } - }.getD(); + public IModelProxy createModelProxy(Object element, IPresentationContext context) { + assert element == this; + return new ModelProxy(this, context.getWindow().getShell().getDisplay()); } @Override - public boolean supportsStorageRetrieval() { - return true; + @SuppressWarnings("rawtypes") + public Object getAdapter(Class adapter) { + if (adapter == IMemoryBlockRetrieval.class) return block_retrieval; + if (adapter == IMemoryBlockRetrievalExtension.class) return block_retrieval; + return super.getAdapter(adapter); } String getMemoryID() { - return exec_ctx.id; + return ctx_id; } void flushAllCaches() { - for (MemoryBlock b : mem_blocks) b.mem_data = null; + mem_data = null; } void onMemoryChanged(boolean suspended) { assert Protocol.isDispatchThread(); - if (mem_blocks.size() == 0) return; - for (MemoryBlock b : mem_blocks) { - if (suspended) b.mem_prev = b.mem_last; - b.mem_data = null; - } + if (suspended) mem_prev = mem_last; + mem_data = null; synchronized (model_proxies) { for (ModelProxy p : model_proxies) { p.onMemoryChanged(suspended); @@ -694,9 +650,25 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { } } - void dispose() { - MemoryBlock[] list = mem_blocks.toArray(new MemoryBlock[mem_blocks.size()]); - for (MemoryBlock b : list) b.close(); + void onContextExited(String id) { + assert Protocol.isDispatchThread(); + if (!id.equals(ctx_id)) return; + expression_value.reset(); + if (remote_expression.isValid() && remote_expression.getData() != null) { + final IChannel channel = model.getChannel(); + if (channel.getState() == IChannel.STATE_OPEN) { + IExpressions exps = channel.getRemoteService(IExpressions.class); + exps.dispose(remote_expression.getData().getID(), new IExpressions.DoneDispose() { + @Override + public void doneDispose(IToken token, Exception error) { + if (error == null) return; + if (channel.getState() != IChannel.STATE_OPEN) return; + Activator.log("Error disposing remote expression evaluator", error); + } + }); + } + remote_expression.reset(); + } } /************************** Persistence ***************************************************/ @@ -717,7 +689,7 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { private static final Map<String,List<Element>> blocks_memento = new HashMap<String,List<Element>>(); private static final Set<Runnable> pending_updates = new HashSet<Runnable>(); - static boolean memento_loaded; + private static boolean memento_loaded; private static void asyncExec(TCFModel model, Runnable r) { synchronized (pending_updates) { @@ -791,18 +763,17 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { } } - static void onMemoryNodeCreated(TCFNodeExecContext exe_ctx) { + static void onMemoryNodeCreated(final TCFNodeExecContext exe_ctx) { assert Protocol.isDispatchThread(); synchronized (blocks_memento) { // Restore memory monitors associated with the node final List<Element> memento = blocks_memento.remove(exe_ctx.id); if (memento == null || memento.size() == 0) return; ArrayList<IMemoryBlock> list = new ArrayList<IMemoryBlock>(); - TCFMemoryBlockRetrieval r = exe_ctx.model.getMemoryBlockRetrieval(exe_ctx); for (Element xml_block : memento) { String expr = xml_block.getAttribute(XML_ATTR_ADDR); long length = Long.parseLong(xml_block.getAttribute(XML_ATTR_SIZE)); - list.add(r.new MemoryBlock(expr, length)); + list.add(exe_ctx.model.getMemoryBlock(exe_ctx.id, expr, length)); } final IMemoryBlock[] blks = list.toArray(new IMemoryBlock[list.size()]); asyncExec(exe_ctx.model, new Runnable() { @@ -861,12 +832,9 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { Map<IMemoryBlock,Element> mb_to_xml = new HashMap<IMemoryBlock,Element>(); Element xml_memory = document.createElement(XML_NODE_MEMORY); for (IMemoryBlock mb : manager.getMemoryBlocks()) { - if (mb instanceof MemoryBlock) { - MemoryBlock m = (MemoryBlock)mb; - TCFMemoryBlockRetrieval r = (TCFMemoryBlockRetrieval)m.getMemoryBlockRetrieval(); - if (r.exec_ctx.model != model) continue; - assert r.exec_ctx.isDisposed(); - assert m.disposed; + if (mb instanceof TCFMemoryBlock) { + TCFMemoryBlock m = (TCFMemoryBlock)mb; + if (m.model != model) continue; Element xml_block = document.createElement(XML_NODE_BLOCK); xml_block.setAttribute(XML_ATTR_CTX, m.ctx_id); xml_block.setAttribute(XML_ATTR_ADDR, m.expression); diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java index f705aa4a7..5ac93be60 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModel.java @@ -22,6 +22,7 @@ import java.util.Set; import java.util.WeakHashMap; import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IExpressionManager; import org.eclipse.debug.core.IExpressionsListener; @@ -37,6 +38,8 @@ import org.eclipse.debug.core.commands.ISuspendHandler; import org.eclipse.debug.core.commands.ITerminateHandler; import org.eclipse.debug.core.model.IDebugModelProvider; import org.eclipse.debug.core.model.IExpression; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IMemoryBlockExtension; import org.eclipse.debug.core.model.IMemoryBlockRetrieval; import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension; import org.eclipse.debug.core.model.ISourceLocator; @@ -246,26 +249,36 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab private final Map<Class<?>,Object> adapters = new HashMap<Class<?>,Object>(); - private class MemoryBlocksUpdate extends TCFDataCache<Map<String,TCFMemoryBlockRetrieval>> { + private final List<TCFMemoryBlock> mem_blocks = new ArrayList<TCFMemoryBlock>(); + private final Map<String,IMemoryBlockRetrievalExtension> mem_retrieval = new HashMap<String,IMemoryBlockRetrievalExtension>(); + private final IMemoryBlockRetrievalExtension mem_not_supported = new IMemoryBlockRetrievalExtension() { + @Override + public boolean supportsStorageRetrieval() { + return false; + } + @Override + public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { + return null; + } + + @Override + public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException { + return null; + } + }; + + + private class MemoryBlocksUpdate implements Runnable { final Set<String> changeset = new HashSet<String>(); final Set<String> suspended = new HashSet<String>(); - MemoryBlocksUpdate(IChannel channel) { - super(channel); - Protocol.invokeLater(new Runnable() { - public void run() { - if (!validate(this)) return; - Map<String,TCFMemoryBlockRetrieval> map = getData(); - if (map != null) { // map can be null if, for example, the channel was closed - for (TCFMemoryBlockRetrieval r : map.values()) { - r.onMemoryChanged(suspended.contains(r.getMemoryID())); - } - } - launch.removePendingClient(mem_blocks_update); - mem_blocks_update = null; - } - }); + MemoryBlocksUpdate() { + mem_blocks_update = this; + Protocol.invokeLater(this); + if (wait_for_views_update_after_step) { + launch.addPendingClient(this); + } } void add(String id, boolean suspended) { @@ -273,39 +286,34 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab if (suspended) this.suspended.add(id); } - public boolean startDataRetrieval() { - // Map changed contexts to memory nodes, and then to memory block retrieval objects - Map<String,TCFMemoryBlockRetrieval> map = new HashMap<String,TCFMemoryBlockRetrieval>(); - for (String id : changeset) { - if (map.get(id) != null) continue; - TCFNode node = id2node.get(id); - if (node == null) { - if (!createNode(id, this)) return false; - if (isValid()) { - Activator.log("Cannot create debug model node", getError()); - reset(); - continue; - } - node = id2node.get(id); - } - if (node instanceof TCFNodeExecContext) { - TCFDataCache<TCFNodeExecContext> c = ((TCFNodeExecContext)node).getMemoryNode(); - if (!c.validate(this)) return false; - node = c.getData(); - if (node == null) continue; - TCFMemoryBlockRetrieval r = mem_retrieval.get(node.id); - if (r != null) { - map.put(node.id, r); - if (suspended.contains(id)) suspended.add(node.id); + public void run() { + assert mem_blocks_update == this; + if (channel.getState() == IChannel.STATE_OPEN && mem_blocks.size() > 0) { + // Map changed contexts to memory nodes, and then to memory block objects + Set<TCFMemoryBlock> set = new HashSet<TCFMemoryBlock>(); + for (String id : changeset) { + if (!createNode(id, this)) return; + TCFNode node = id2node.get(id); + if (node instanceof TCFNodeExecContext) { + TCFDataCache<TCFNodeExecContext> c = ((TCFNodeExecContext)node).getMemoryNode(); + if (!c.validate(this)) return; + node = c.getData(); + if (node == null) continue; + for (TCFMemoryBlock b : mem_blocks) { + if (b.getMemoryID().equals(node.id)) { + if (suspended.contains(id)) suspended.add(node.id); + set.add(b); + } + } } } + for (TCFMemoryBlock b : set) b.onMemoryChanged(suspended.contains(b.getMemoryID())); } - set(null, null, map); - return true; + launch.removePendingClient(this); + mem_blocks_update = null; } } - private final Map<String,TCFMemoryBlockRetrieval> mem_retrieval = new HashMap<String,TCFMemoryBlockRetrieval>(); private MemoryBlocksUpdate mem_blocks_update; private final Map<String,String> cast_to_type_map = new HashMap<String,String>(); @@ -798,7 +806,7 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab } } view_request_listeners = l.size() > 0 ? l : null; - TCFMemoryBlockRetrieval.onModelCreated(this); + TCFMemoryBlock.onModelCreated(this); } /** @@ -830,11 +838,12 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab TCFNodeExecContext ctx = cache.getData(); if (!ctx.getMemoryContext().validate(this)) return; if (ctx.getMemoryContext().getError() == null) { - o = getMemoryBlockRetrieval(ctx); + o = getMemoryBlockRetrieval(ctx.id); } } } - assert o == null || adapter.isInstance(o); + if (o == null) o = mem_not_supported; + assert adapter.isInstance(o); done(o); } }.getE(); @@ -842,11 +851,53 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab return null; } - TCFMemoryBlockRetrieval getMemoryBlockRetrieval(TCFNodeExecContext node) { - TCFMemoryBlockRetrieval r = mem_retrieval.get(node.id); + TCFMemoryBlock getMemoryBlock(String id, String expression, long length) { + assert Protocol.isDispatchThread(); + IMemoryBlockRetrievalExtension r = getMemoryBlockRetrieval(id); + TCFMemoryBlock b = new TCFMemoryBlock(this, r, id, expression, length); + mem_blocks.add(b); + return b; + } + + private IMemoryBlockRetrievalExtension getMemoryBlockRetrieval(final String id) { + /* + * Note: platform uses MemoryBlockRetrieval objects to link memory blocks with selection in the Debug view. + * We need to maintain 1 to 1 mapping between memory context IDs and MemoryBlockRetrieval objects. + */ + assert Protocol.isDispatchThread(); + IMemoryBlockRetrievalExtension r = mem_retrieval.get(id); if (r == null) { - r = new TCFMemoryBlockRetrieval(node); - mem_retrieval.put(node.id, r); + r = new IMemoryBlockRetrievalExtension() { + @Override + public IMemoryBlockExtension getExtendedMemoryBlock(final String expression, Object context) throws DebugException { + final IMemoryBlockRetrieval r = this; + return new TCFDebugTask<IMemoryBlockExtension>() { + @Override + public void run() { + TCFMemoryBlock b = new TCFMemoryBlock(TCFModel.this, r, id, expression, -1); + mem_blocks.add(b); + done(b); + } + }.getD(); + } + @Override + public IMemoryBlock getMemoryBlock(final long address, final long length) throws DebugException { + final IMemoryBlockRetrieval r = this; + return new TCFDebugTask<IMemoryBlock>() { + @Override + public void run() { + TCFMemoryBlock b = new TCFMemoryBlock(TCFModel.this, r, id, "0x" + Long.toHexString(address), length); + mem_blocks.add(b); + done(b); + } + }.getD(); + } + @Override + public boolean supportsStorageRetrieval() { + return true; + } + }; + mem_retrieval.put(id, r); } return r; } @@ -912,12 +963,12 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab launch_node = null; } // Dispose memory monitors - for (TCFMemoryBlockRetrieval r : mem_retrieval.values()) r.dispose(); + TCFMemoryBlock.onModelDisconnected(this); mem_retrieval.clear(); + mem_blocks.clear(); // Refresh the Debug view - cannot be done through ModelProxy since it is disposed refreshLaunchView(); assert id2node.size() == 0; - TCFMemoryBlockRetrieval.onModelDisconnected(this); } void onProcessOutput(String ctx_id, int stream_id, byte[] data) { @@ -988,13 +1039,7 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab } } } - if (mem_retrieval.size() == 0) return; - if (mem_blocks_update == null) { - mem_blocks_update = new MemoryBlocksUpdate(channel); - if (wait_for_views_update_after_step) { - launch.addPendingClient(mem_blocks_update); - } - } + if (mem_blocks_update == null) new MemoryBlocksUpdate(); mem_blocks_update.add(id, context_suspended); } @@ -1210,9 +1255,8 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab void removeNode(String id) { assert id != null; assert Protocol.isDispatchThread(); + for (TCFMemoryBlock b : mem_blocks) b.onContextExited(id); id2node.remove(id); - TCFMemoryBlockRetrieval r = mem_retrieval.remove(id); - if (r != null) r.dispose(); } void flushAllCaches() { @@ -1225,7 +1269,7 @@ public class TCFModel implements ITCFModel, IElementContentProvider, IElementLab participant.sourceContainersChanged(d); } } - for (TCFMemoryBlockRetrieval b : mem_retrieval.values()) b.flushAllCaches(); + for (TCFMemoryBlock b : mem_blocks) b.flushAllCaches(); for (TCFNode n : id2node.values()) n.flushAllCaches(); launch_node.flushAllCaches(); } diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModelManager.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModelManager.java index 1df6f12b6..9c363a9ce 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModelManager.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFModelManager.java @@ -143,7 +143,7 @@ public class TCFModelManager { } } } - TCFMemoryBlockRetrieval.onWorkbenchShutdown(); + TCFMemoryBlock.onWorkbenchShutdown(); return true; } diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java index 5147366fe..cc59d41b5 100644 --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/model/TCFNodeExecContext.java @@ -501,7 +501,7 @@ public class TCFNodeExecContext extends TCFNode implements ISymbolOwner, ITCFExe return true; } }; - TCFMemoryBlockRetrieval.onMemoryNodeCreated(this); + TCFMemoryBlock.onMemoryNodeCreated(this); updateTerminal(); } |