From 4ea1ca73505dfb21b260bd4c758eaaea0c29dcb2 Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Wed, 27 Jun 2007 23:41:42 +0000 Subject: [PATCH] Committed patch to enable IMemoryBlockExtension support (from bug 160046). --- .../dd/dsf/debug/model/DsfMemoryBlock.java | 340 ++++++++++++++++-- .../debug/model/DsfMemoryBlockRetrieval.java | 216 ++++++++--- .../eclipse/dd/dsf/debug/service/IMemory.java | 20 ++ 3 files changed, 493 insertions(+), 83 deletions(-) diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlock.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlock.java index 9a7e71897fe..dd5a55867a8 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlock.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlock.java @@ -7,64 +7,64 @@ * * Contributors: * Wind River Systems - initial API and implementation + * Ericsson Communication - upgrade IF from IMemoryBlock to IMemoryBlockExtension *******************************************************************************/ package org.eclipse.dd.dsf.debug.model; -import org.eclipse.core.runtime.IStatus; +import java.math.BigInteger; +import java.util.concurrent.ExecutionException; + +import org.eclipse.cdt.utils.Addr32; import org.eclipse.core.runtime.PlatformObject; -import org.eclipse.core.runtime.Status; -import org.eclipse.dd.dsf.debug.DsfDebugPlugin; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.debug.service.IMemory; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IDebugTarget; -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.MemoryByte; -public class DsfMemoryBlock extends PlatformObject implements IMemoryBlock +/** + * This class holds the memory block retrieved from the target as a result of + * a getBytes() or getBytesFromAddress() call from the platform. + */ +public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtension { private final DsfMemoryBlockRetrieval fRetrieval; private final String fModelId; + private final String fExpression; private final long fStartAddress; - private final byte[] fBytes; + private final long fLength; + private final BigInteger fBaseAddress; - DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, String modelId, long startAddress, byte[] bytes) { + /** + * Constructor + * + * @param retrieval + * @param modelId + * @param expression + * @param startAddress + * @param length + */ + DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, String modelId, String expression, long startAddress, long length) { fRetrieval = retrieval; fModelId = modelId; + fExpression = expression; fStartAddress = startAddress; - fBytes = bytes; - } - - public byte[] getBytes() throws DebugException { - return fBytes; + fBaseAddress = new BigInteger(Long.toString(startAddress)); + fLength = length; } - public long getLength() { - return fBytes.length; - } + // //////////////////////////////////////////////////////////////////////// + // IAdaptable + // //////////////////////////////////////////////////////////////////////// - public long getStartAddress() { - return fStartAddress; - } - - public void setValue(long offset, byte[] bytes) throws DebugException { - throw new DebugException(new Status(IStatus.ERROR, DsfDebugPlugin.PLUGIN_ID, DebugException.NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$ - } - - public boolean supportsValueModification() { - return false; - } - - public IDebugTarget getDebugTarget() { - return null; - } - - public ILaunch getLaunch() { - return null; - } - - public String getModelIdentifier() { - return fModelId; - } - + /* (non-Javadoc) + * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) + */ @Override public Object getAdapter(Class adapter) { if (adapter.isAssignableFrom(DsfMemoryBlockRetrieval.class)) { @@ -72,4 +72,266 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlock } return super.getAdapter(adapter); } + + // //////////////////////////////////////////////////////////////////////// + // IDebugElement + // //////////////////////////////////////////////////////////////////////// + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() + */ + public IDebugTarget getDebugTarget() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier() + */ + public String getModelIdentifier() { + return fModelId; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() + */ + public ILaunch getLaunch() { + return null; + } + + // //////////////////////////////////////////////////////////////////////// + // IMemoryBock interface - obsoleted by IMemoryBlockExtension + // //////////////////////////////////////////////////////////////////////// + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlock#getStartAddress() + */ + public long getStartAddress() { + return fStartAddress; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlock#getLength() + */ + public long getLength() { + return fLength; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlock#getBytes() + */ + public byte[] getBytes() throws DebugException { + MemoryByte[] block = fetchMemoryBlock(fStartAddress, fLength); + int length = block.length; + byte[] bytes = new byte[length]; + // Extract bytes from MemoryBytes + for (int i = 0; i < length; i++) + bytes[i] = block[i].getValue(); + return bytes; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlock#supportsValueModification() + */ + public boolean supportsValueModification() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlock#setValue(long, byte[]) + */ + public void setValue(long offset, byte[] bytes) throws DebugException { + setValue(BigInteger.valueOf(offset), bytes); + } + + // //////////////////////////////////////////////////////////////////////// + // IMemoryBlockExtension interface + // //////////////////////////////////////////////////////////////////////// + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getExpression() + */ + public String getExpression() { + return fExpression; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBigBaseAddress() + */ + public BigInteger getBigBaseAddress() throws DebugException { + return fBaseAddress; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockStartAddress() + */ + public BigInteger getMemoryBlockStartAddress() throws DebugException { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockEndAddress() + */ + public BigInteger getMemoryBlockEndAddress() throws DebugException { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBigLength() + */ + public BigInteger getBigLength() throws DebugException { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getAddressSize() + */ + public int getAddressSize() throws DebugException { + // TODO: Have the service make a trip to the back-end and + // retrieve/store that information for us + return 4; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#supportBaseAddressModification() + */ + public boolean supportBaseAddressModification() throws DebugException { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#supportsChangeManagement() + */ + public boolean supportsChangeManagement() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#setBaseAddress(java.math.BigInteger) + */ + public void setBaseAddress(BigInteger address) throws DebugException { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBytesFromOffset(java.math.BigInteger, long) + */ + public MemoryByte[] getBytesFromOffset(BigInteger unitOffset, long addressableUnits) throws DebugException { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBytesFromAddress(java.math.BigInteger, long) + */ + public MemoryByte[] getBytesFromAddress(BigInteger address, long units) throws DebugException { + return fetchMemoryBlock(address.longValue(), units); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#setValue(java.math.BigInteger, byte[]) + */ + public void setValue(BigInteger offset, byte[] bytes) throws DebugException { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#connect(java.lang.Object) + */ + public void connect(Object client) { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#disconnect(java.lang.Object) + */ + public void disconnect(Object client) { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getConnections() + */ + public Object[] getConnections() { + // TODO Auto-generated method stub + return new Object[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#dispose() + */ + public void dispose() throws DebugException { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockRetrieval() + */ + public IMemoryBlockRetrieval getMemoryBlockRetrieval() { + return fRetrieval; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getAddressableSize() + */ + public int getAddressableSize() throws DebugException { + // TODO: Have the service make a trip to the back-end and + // retrieve/store that information for us + return 1; + } + + // //////////////////////////////////////////////////////////////////////// + // Helper functions + // //////////////////////////////////////////////////////////////////////// + + /* The real thing. Since the original call is synchronous (from a platform Job), + * we use a Query that will patiently wait for the underlying asynchronous calls + * to complete before returning. + * + * @param address + * @param length + * @return MemoryBytes[] + * @throws DebugException + */ + private MemoryByte[] fetchMemoryBlock(final long address, final long length) throws DebugException { + + /* For this first implementation, we make a few simplifying assumptions: + * - word_size = 1 (we want to read individual bytes) + * - offset = 0 + * - mode = hexadecimal (will be overridden in getMemory() anyway) + */ + final int word_size = 1; + final int offset = 0; + final int mode = 0; // TODO: Add a constant for hexadecimal mode + + // Use a Query to "synchronize" the inherently asynchronous downstream calls + Query query = new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + IMemory memoryService = (IMemory) fRetrieval.getServiceTracker().getService(); + if (memoryService != null) { + // Place holder for the result + final MemoryByte[] buffer = new MemoryByte[(int) length]; + // Go for it + memoryService.getMemory( + fRetrieval.getContext(), new Addr32(address), word_size, buffer, offset, (int) length, mode, + new RequestMonitor(fRetrieval.getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(buffer); + rm.done(); + } + }); + } + + } + }; + fRetrieval.getExecutor().execute(query); + try { + return query.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + return null; + } + } diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java index d6418bb0aa9..41574b32b49 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java @@ -7,19 +7,14 @@ * * Contributors: * Wind River Systems - initial API and implementation + * Ericsson Communication - upgrade IF from IMemoryBlockRetrieval to IMemoryBlockRetrievalExtension *******************************************************************************/ package org.eclipse.dd.dsf.debug.model; -import java.util.concurrent.ExecutionException; - -import org.eclipse.cdt.utils.Addr32; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.core.runtime.Status; -import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DsfExecutor; -import org.eclipse.dd.dsf.concurrent.Query; -import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.debug.DsfDebugPlugin; import org.eclipse.dd.dsf.debug.service.IMemory; @@ -27,24 +22,40 @@ import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.service.IDsfService; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IMemoryBlock; -import org.eclipse.debug.core.model.IMemoryBlockRetrieval; +import org.eclipse.debug.core.model.IMemoryBlockExtension; +import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.util.tracker.ServiceTracker; /** * Implementation of memory access API of the Eclipse standard debug model. - *
Note: This is only a sample implementation intended as a starting point. + * + * The IMemoryBlockRetrievalExtension is implemented for the reference + * application. This will result in getExtendedMemoryBlock() being called + * when a memory block is selected from the memory pane. + * + * However, if the 'simpler' IMemoryBlockRetrieval is to be implemented, the + * code will still be functional after trivial adjustments. In that case, the + * platform will call getMemoryBlock() instead. Note that DsfMemoryBlock will + * have to be 'downgraded' to implement IMemoryBlock (instead of IMemoryBlockExtension) + * */ -public class DsfMemoryBlockRetrieval extends PlatformObject - implements IMemoryBlockRetrieval +public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBlockRetrievalExtension { - private final String fModelId; - private final DsfSession fSession; - private final DsfExecutor fExecutor; - private final IDMContext fContext; - private final ServiceTracker fServiceTracker; + private final String fModelId; + private final DsfSession fSession; + private final DsfExecutor fExecutor; + private final IDMContext fContext; + private final ServiceTracker fServiceTracker; + /** + * Constructor + * + * @param modelId + * @param dmc + * @throws DebugException + */ public DsfMemoryBlockRetrieval(String modelId, IDMContext dmc) throws DebugException { fModelId = modelId; fContext = dmc; @@ -66,37 +77,154 @@ public class DsfMemoryBlockRetrieval extends PlatformObject } fServiceTracker.open(); } - - public IMemoryBlock getMemoryBlock(final long startAddress, final long length) throws DebugException { - Query query = new Query() { - @Override - protected void execute(final DataRequestMonitor rm) { - IMemory memoryService = (IMemory)fServiceTracker.getService(); - if (memoryService != null) { - final byte[] buf = new byte[(int)length]; - memoryService.getMemory( - fContext, new Addr32(startAddress), 32, buf, 0, (int)length, 0, - new RequestMonitor(fExecutor, rm) { - @Override - protected void handleOK() { - rm.setData(new DsfMemoryBlock(DsfMemoryBlockRetrieval.this, fModelId, startAddress, buf)); - rm.done(); - } - }); - } - - } - }; - fExecutor.execute(query); - try { - return query.get(); - } catch (InterruptedException e) { - } catch (ExecutionException e) { - } - return null; - } + // //////////////////////////////////////////////////////////////////////// + // Accessors + // //////////////////////////////////////////////////////////////////////// + + /** + * + * @return + */ + public String getModelId() { + return fModelId; + } + + /** + * + * @return + */ + public DsfSession getSession() { + return fSession; + } + + /** + * + * @return + */ + public DsfExecutor getExecutor() { + return fExecutor; + } + + /** + * + * @return + */ + public IDMContext getContext() { + return fContext; + } + + /** + * + * @return + */ + public ServiceTracker getServiceTracker() { + return fServiceTracker; + } + + // //////////////////////////////////////////////////////////////////////// + // IMemoryBlockRetrieval - obsoleted by IMemoryBlockRetrievalExtension + // //////////////////////////////////////////////////////////////////////// + + /* + * (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval() + */ public boolean supportsStorageRetrieval() { return true; } + + /* + * (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long) + */ + public IMemoryBlock getMemoryBlock(final long startAddress, final long length) throws DebugException { + // The expression to display in the rendering tab + // Put here for the sake of completeness (not used with IMemoryBlock) + String expression = "0x" + Long.toHexString(startAddress); //$NON-NLS-1$ + return new DsfMemoryBlock(DsfMemoryBlockRetrieval.this, fModelId, expression, startAddress, length); + } + + // //////////////////////////////////////////////////////////////////////// + // IMemoryBlockRetrievalExtension + // //////////////////////////////////////////////////////////////////////// + + /* + * (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension#getExtendedMemoryBlock(java.lang.String, java.lang.Object) + */ + public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException { + + boolean validAddress = false; + long address = 0; + + /* See if the expression is a simple numeric value; if it is, we can + * avoid some costly processing (calling the back-end to resolve the + * expression and obtain an address) + */ + try { + // First, assume a decimal address (not too realistic but bear with us :-) + int base = 10; + int offset = 0; + + // Check for "hexadecimality" + if (expression.startsWith("0x") || expression.startsWith("0X")) { //$NON-NLS-1$//$NON-NLS-2$ + base = 16; + offset = 2; + } + + // Now, try to parse the expression. If a NumberFormatException is thrown, + // then it wasn't a simple numerical expression and we go to plan B + address = Long.parseLong(expression.substring(offset), base); + + // All right! We saved a trip to the back-end. + validAddress = true; + + } catch (NumberFormatException nfexc) { + // OK, expression is not a simple, absolute numeric value; try to resolve as expression + } + + // We have to ask the debugger to resolve the address for us + if (!validAddress) { + // [frch] Code removed until we properly hook the ExpressionService + // [frch] Code saved in lmcfrch-memory-070625.PATCH + return null; + } + + /* At this point, we only know the requested address and we have no + * idea of the memory block length. The renderer will provide this + * information when it calls getBytesFromAddress() i.e. after the + * memory block holder has been instantiated... + * + * We could try to out-smart the renderer and do some educated guess + * about the start address it will select and the length it will + * request. + * + * This would 'work' for the standard debug renderers: start address + * on a 16-byte boundary, length of 320 bytes (20 lines of 16 bytes). + * However, this is not such a great idea: a given renderer might ask + * for a block starting at any address adn length it sees fit. Therefore + * we can't make any assumption. + * + * The only safe approach is to just instantiate the IMemoryBlockExtension + * and postpone the actual memory fetch until the renderer explicitly + * asks for it (i.e. calls getBytesFromAddress()). + * + * The down side is that every time we switch renderer, for the same block, + * a trip to the target could result. + * + * However, we have an ace in our sleeve: the memory request cache should + * save us a trip to the back-end. + */ + + return new DsfMemoryBlock(DsfMemoryBlockRetrieval.this, fModelId, expression, address, 0); + } + + // //////////////////////////////////////////////////////////////////////// + // Helper functions + // //////////////////////////////////////////////////////////////////////// + + // [frch] Code removed until we properly hook the ExpressionService + // [frch] Code saved in lmcfrch-memory-070625.PATCH + } diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMemory.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMemory.java index df3ccbcbb4b..d1ac1282c8f 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMemory.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IMemory.java @@ -7,6 +7,7 @@ * * Contributors: * Wind River Systems - initial API and implementation + * Ericsson Communication - extended the API for IMemoryBlockExtension *******************************************************************************/ package org.eclipse.dd.dsf.debug.service; @@ -14,6 +15,7 @@ import org.eclipse.cdt.core.IAddress; import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.debug.core.model.MemoryByte; /** * Service for accessing memory. Memory contexts are not meant to be @@ -38,5 +40,23 @@ public interface IMemory extends IDsfService { */ public void fillMemory(IDMContext ctx, IAddress addr, int word_size, byte[] value, int size, int mode, RequestMonitor requestMonitor); + + // //////////////////////////////////////////////////////////////////////// + // Replicated the base functions to support IMemoryBlockExtension + // //////////////////////////////////////////////////////////////////////// + + /** Writes the given value to the given memory location. */ + public void setMemory(IDMContext ctx, IAddress addr, + int word_size, MemoryByte[] buf, int offs, int size, int mode, RequestMonitor requestMonitor); + + /** Reads memory at the given location */ + public void getMemory(IDMContext ctx, IAddress addr, + int word_size, MemoryByte[] buf, int offs, int size, int mode, RequestMonitor requestMonitor); + + public void fillMemory(IDMContext ctx, IAddress addr, + int word_size, MemoryByte[] value, int size, int mode, RequestMonitor requestMonitor); + +// /** Reads memory at the given location */ +// public void resolveMemoryAddress(IDMContext ctx, String expression, BigInteger[] address, RequestMonitor requestMonitor); }