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 dd5a55867a8..a6027c0bd0c 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,20 +7,26 @@ * * Contributors: * Wind River Systems - initial API and implementation - * Ericsson Communication - upgrade IF from IMemoryBlock to IMemoryBlockExtension + * Ericsson Communication - upgrade IF to IMemoryBlockExtension + * Ericsson Communication - added support for 64 bit processors *******************************************************************************/ package org.eclipse.dd.dsf.debug.model; import java.math.BigInteger; import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; -import org.eclipse.cdt.utils.Addr32; import org.eclipse.core.runtime.PlatformObject; 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.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IMemory.MemoryChangedEvent; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IMemoryBlockExtension; @@ -28,34 +34,46 @@ import org.eclipse.debug.core.model.IMemoryBlockRetrieval; import org.eclipse.debug.core.model.MemoryByte; /** - * This class holds the memory block retrieved from the target as a result of - * a getBytes() or getBytesFromAddress() call from the platform. + * This class manages the memory block retrieved from the target as a result + * of a getBytesFromAddress() call from the platform. + * + * It performs its read/write functions using the MemoryService. */ -public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtension +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 long fLength; - private final BigInteger fBaseAddress; - + private final String fModelId; + private final String fExpression; + private final BigInteger fStartAddress; + private BigInteger fEndAddress; + private long fLength = 0; + /** - * Constructor + * Constructor. * - * @param retrieval - * @param modelId - * @param expression - * @param startAddress - * @param length + * @param retrieval - the MemoryBlockRetrieval (session context) + * @param modelId - + * @param expression - the displayed expression + * @param startAddress - the actual memory block start address + * @param length - the memory block length (could be 0) */ - DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, String modelId, String expression, long startAddress, long length) { - fRetrieval = retrieval; - fModelId = modelId; - fExpression = expression; + DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, String modelId, String expression, BigInteger startAddress, long length) { + fRetrieval = retrieval; + fModelId = modelId; + fExpression = expression; fStartAddress = startAddress; - fBaseAddress = new BigInteger(Long.toString(startAddress)); - fLength = length; + fEndAddress = startAddress.add(BigInteger.valueOf(length)); + fLength = length; + + try { + fRetrieval.getExecutor().execute(new Runnable() { + public void run() { + fRetrieval.getSession().addServiceEventListener(DsfMemoryBlock.this, null); + } + }); + } catch(RejectedExecutionException e) { + // Session is shut down. + } } // //////////////////////////////////////////////////////////////////////// @@ -65,7 +83,8 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens /* (non-Javadoc) * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) */ - @Override + @SuppressWarnings("unchecked") + @Override public Object getAdapter(Class adapter) { if (adapter.isAssignableFrom(DsfMemoryBlockRetrieval.class)) { return fRetrieval; @@ -81,6 +100,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() */ public IDebugTarget getDebugTarget() { + // FRCH: return fRetrieval.getDebugTarget(); return null; } @@ -95,6 +115,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() */ public ILaunch getLaunch() { + // FRCH: return fRetrieval.getDebugTarget().getLaunch(); return null; } @@ -106,13 +127,20 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IMemoryBlock#getStartAddress() */ public long getStartAddress() { - return fStartAddress; + // Warning: doesn't support 64-bit addresses + long address = fStartAddress.longValue(); + if (fStartAddress.equals(BigInteger.valueOf(address))) + return address; + + // FRCH: Should we throw an exception instead? + return 0; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IMemoryBlock#getLength() */ public long getLength() { + // Warning: could return 0 return fLength; } @@ -124,7 +152,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens int length = block.length; byte[] bytes = new byte[length]; // Extract bytes from MemoryBytes - for (int i = 0; i < length; i++) + for (int i : bytes) bytes[i] = block[i].getValue(); return bytes; } @@ -140,7 +168,10 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IMemoryBlock#setValue(long, byte[]) */ public void setValue(long offset, byte[] bytes) throws DebugException { - setValue(BigInteger.valueOf(offset), bytes); + if (offset <= Integer.MAX_VALUE) + writeMemoryBlock((int) offset, bytes); + + // FRCH: Should we throw an exception if offset is too large? } // //////////////////////////////////////////////////////////////////////// @@ -158,13 +189,14 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBigBaseAddress() */ public BigInteger getBigBaseAddress() throws DebugException { - return fBaseAddress; + return fStartAddress; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockStartAddress() */ public BigInteger getMemoryBlockStartAddress() throws DebugException { + // "null" indicates that memory can be retrieved at addresses lower than the block base address return null; } @@ -172,6 +204,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockEndAddress() */ public BigInteger getMemoryBlockEndAddress() throws DebugException { + // "null" indicates that memory can be retrieved at addresses higher the block base address return null; } @@ -179,15 +212,15 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBigLength() */ public BigInteger getBigLength() throws DebugException { - return null; + // -1 indicates that memory block is unbounded + return BigInteger.ONE.negate(); } /* (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 + // FRCH: return fRetrieval.getDebugTarget().getAddressSize(); return 4; } @@ -195,14 +228,14 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IMemoryBlockExtension#supportBaseAddressModification() */ public boolean supportBaseAddressModification() throws DebugException { - return true; + return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IMemoryBlockExtension#supportsChangeManagement() */ public boolean supportsChangeManagement() { - return true; + return false; } /* (non-Javadoc) @@ -215,23 +248,29 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens /* (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; + public MemoryByte[] getBytesFromOffset(BigInteger offset, long units) throws DebugException { + return getBytesFromAddress(fStartAddress.add(offset), units); } /* (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); + fLength = units; + fEndAddress = fStartAddress.add(BigInteger.valueOf(units)); + return fetchMemoryBlock(address, 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 + // Ensure that the offset can be cast into an int + int offs = offset.intValue(); + if (offset.equals(BigInteger.valueOf(offs))) + writeMemoryBlock(offs, bytes); + + // FRCH: Should we throw an exception if offset is too large? } /* (non-Javadoc) @@ -260,7 +299,15 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @see org.eclipse.debug.core.model.IMemoryBlockExtension#dispose() */ public void dispose() throws DebugException { - // TODO Auto-generated method stub + try { + fRetrieval.getExecutor().execute(new Runnable() { + public void run() { + fRetrieval.getSession().removeServiceEventListener(DsfMemoryBlock.this); + } + }); + } catch(RejectedExecutionException e) { + // Session is shut down. + } } /* (non-Javadoc) @@ -274,8 +321,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @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 + // FRCH: return fRetrieval.getDebugTarget().getAddressableSize(); return 1; } @@ -283,25 +329,25 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens // 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 { + /* + * 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 MemoryByte[] @throws DebugException + */ + private MemoryByte[] fetchMemoryBlock(final BigInteger address, final long length) throws DebugException { - /* For this first implementation, we make a few simplifying assumptions: + /* FRCH: Fix the loose ends... + * + * 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) + * - offset = 0 + * - mode = 0 (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 + final int offset = 0; + final int mode = 0; // Use a Query to "synchronize" the inherently asynchronous downstream calls Query query = new Query() { @@ -313,7 +359,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens final MemoryByte[] buffer = new MemoryByte[(int) length]; // Go for it memoryService.getMemory( - fRetrieval.getContext(), new Addr32(address), word_size, buffer, offset, (int) length, mode, + fRetrieval.getContext(), address, word_size, buffer, offset, (int) length, mode, new RequestMonitor(fRetrieval.getExecutor(), rm) { @Override protected void handleOK() { @@ -334,4 +380,53 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens return null; } + @DsfServiceEventHandler + public void eventDispatched(MemoryChangedEvent e) { + handleMemoryChange(e.getAddress()); + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.ISuspendedDMEvent e) { + handleMemoryChange(BigInteger.ZERO); + } + + /* Writes an array of bytes to memory. + * + * @param offset + * @param bytes + * @throws DebugException + */ + private void writeMemoryBlock(final int offset, final byte[] bytes) throws DebugException { + + final int word_size = 1; + final int mode = 0; + + IMemory memoryService = (IMemory) fRetrieval.getServiceTracker().getService(); + if (memoryService != null) { + memoryService.setMemory( + fRetrieval.getContext(), fStartAddress, word_size, bytes, offset, bytes.length, mode, + new RequestMonitor(fRetrieval.getExecutor(), null) { + @Override + protected void handleOK() { + handleMemoryChange(fStartAddress); + } + }); + } + } + + /** + * @param address + * @param length + */ + public void handleMemoryChange(BigInteger address) { + // Check if the change affects this particular block (0 is universal) + if (address.equals(BigInteger.ZERO) || + ((fStartAddress.compareTo(address) != 1) && (fEndAddress.compareTo(address) == 1))) + { + // Notify the event listeners + DebugEvent debugEvent = new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT); + DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { debugEvent }); + } + } + } 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 41574b32b49..f759650742a 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,17 +7,32 @@ * * Contributors: * Wind River Systems - initial API and implementation - * Ericsson Communication - upgrade IF from IMemoryBlockRetrieval to IMemoryBlockRetrievalExtension + * Ericsson Communication - upgrade IF to IMemoryBlockRetrievalExtension + * Ericsson Communication - added Expression evaluation + * Ericsson Communication - added support for 64 bit processors + * Ericsson Communication - added support for event handling *******************************************************************************/ package org.eclipse.dd.dsf.debug.model; +import java.math.BigInteger; +import java.util.concurrent.ExecutionException; + +import org.eclipse.core.runtime.IAdaptable; 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.datamodel.IDMContext; import org.eclipse.dd.dsf.debug.DsfDebugPlugin; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; import org.eclipse.dd.dsf.debug.service.IMemory; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMData; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.service.IDsfService; import org.eclipse.debug.core.DebugException; @@ -30,79 +45,103 @@ import org.osgi.util.tracker.ServiceTracker; /** * Implementation of memory access API of the Eclipse standard debug model. - * - * 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. + * + * The DsfMemoryBlockRetrieval is not an actual memory block but rather a + * reference to the memory address space for an execution context (e.g. a + * process) within a debug session. From this debug 'context', memory blocks + * can then be read/written. + * + * Note: For the reference application, The IMemoryBlockRetrievalExtension + * is implemented. This will result in getExtendedMemoryBlock() being called + * when a memory block is selected from the platform 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) + * code will still be functional after some trivial adjustments. * */ -public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBlockRetrievalExtension +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; - - /** - * Constructor - * - * @param modelId - * @param dmc - * @throws DebugException - */ - public DsfMemoryBlockRetrieval(String modelId, IDMContext dmc) throws DebugException { - fModelId = modelId; - fContext = dmc; - fSession = DsfSession.getSession(fContext.getSessionId()); - if (fSession == null) { - throw new IllegalArgumentException("Session for context " + fContext + " is not active"); //$NON-NLS-1$ //$NON-NLS-2$ - } - fExecutor = fSession.getExecutor(); - String memoryServiceFilter = - "(&" + //$NON-NLS-1$ - "(OBJECTCLASS=" + IMemory.class.getName() + ")" + //$NON-NLS-1$//$NON-NLS-2$ - "(" + IDsfService.PROP_SESSION_ID + "=" + dmc.getSessionId() + ")" + //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - ")"; //$NON-NLS-1$ - BundleContext bundle = DsfDebugPlugin.getBundleContext(); - try { - fServiceTracker = new ServiceTracker(bundle, bundle.createFilter(memoryServiceFilter), null); - } catch (InvalidSyntaxException e) { - throw new DebugException(new Status(IStatus.ERROR, DsfDebugPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, "Error creating service filter.", e)); //$NON-NLS-1$ - } - fServiceTracker.open(); - } + private final String fModelId; + private final DsfSession fSession; + private final DsfExecutor fExecutor; + private IDMContext fContext; + private final ServiceTracker fMemoryServiceTracker; + private final ServiceTracker fExpressionServiceTracker; - // //////////////////////////////////////////////////////////////////////// - // Accessors - // //////////////////////////////////////////////////////////////////////// - /** + * Constructor * - * @return + * @param modelId + * @param dmc + * @throws DebugException */ - public String getModelId() { - return fModelId; + public DsfMemoryBlockRetrieval(String modelId, IDMContext dmc) throws DebugException { + + fModelId = modelId; + fContext = dmc; + fSession = DsfSession.getSession(fContext.getSessionId()); + if (fSession == null) { + throw new IllegalArgumentException( + "Session for context " + fContext + " is not active"); //$NON-NLS-1$ //$NON-NLS-2$ + } + fExecutor = fSession.getExecutor(); + BundleContext bundle = DsfDebugPlugin.getBundleContext(); + + // Here we chose to use 2 distinct service trackers instead of an + // amalgamated one because it is less error prone (and we are lazy). + + // Create a tracker for the MemoryService + String memoryServiceFilter = "(&" + //$NON-NLS-1$ + "(OBJECTCLASS=" //$NON-NLS-1$ + + IMemory.class.getName() + + ")" + //$NON-NLS-1$ + "(" + IDsfService.PROP_SESSION_ID //$NON-NLS-1$ + + "=" + dmc.getSessionId() + ")" + //$NON-NLS-1$//$NON-NLS-2$ + ")"; //$NON-NLS-1$ + + try { + fMemoryServiceTracker = new ServiceTracker( + bundle, bundle.createFilter(memoryServiceFilter), null); + } catch (InvalidSyntaxException e) { + throw new DebugException(new Status(IStatus.ERROR, + DsfDebugPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, + "Error creating service filter.", e)); //$NON-NLS-1$ + } + fMemoryServiceTracker.open(); + + // Create a tracker for the ExpressionService + String expressionServiceFilter = "(&" + //$NON-NLS-1$ + "(OBJECTCLASS=" //$NON-NLS-1$ + + IExpressions.class.getName() + + ")" + //$NON-NLS-1$ + "(" + IDsfService.PROP_SESSION_ID //$NON-NLS-1$ + + "=" + dmc.getSessionId() + ")" + //$NON-NLS-1$//$NON-NLS-2$ + ")"; //$NON-NLS-1$ + + try { + fExpressionServiceTracker = new ServiceTracker( + bundle, bundle.createFilter(expressionServiceFilter), null); + } catch (InvalidSyntaxException e) { + throw new DebugException(new Status(IStatus.ERROR, + DsfDebugPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, + "Error creating service filter.", e)); //$NON-NLS-1$ + } + fExpressionServiceTracker.open(); } - /** - * - * @return - */ - public DsfSession getSession() { - return fSession; - } + // //////////////////////////////////////////////////////////////////////// + // Accessors + // //////////////////////////////////////////////////////////////////////// + public DsfSession getSession() { + return fSession; + } + /** * * @return */ - public DsfExecutor getExecutor() { + public DsfExecutor getExecutor() { return fExecutor; } @@ -110,121 +149,177 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl * * @return */ - public IDMContext getContext() { + public IDMContext getContext() { return fContext; } - /** + /** * * @return */ - public ServiceTracker getServiceTracker() { - return fServiceTracker; + public ServiceTracker getServiceTracker() { + return fMemoryServiceTracker; } - // //////////////////////////////////////////////////////////////////////// - // IMemoryBlockRetrieval - obsoleted by IMemoryBlockRetrievalExtension - // //////////////////////////////////////////////////////////////////////// - - /* - * (non-Javadoc) - * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval() - */ - public boolean supportsStorageRetrieval() { - return true; - } + // //////////////////////////////////////////////////////////////////////// + // IMemoryBlockRetrieval - obsoleted by IMemoryBlockRetrievalExtension + // //////////////////////////////////////////////////////////////////////// - /* - * (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) + * + * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval() */ - public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException { + public boolean supportsStorageRetrieval() { + return true; + } - boolean validAddress = false; - long address = 0; + /* + * (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 IMemoryBlockExtension) + String expression = "0x" + Long.toHexString(startAddress); //$NON-NLS-1$ + return new DsfMemoryBlock(this, fModelId, expression, BigInteger.valueOf(startAddress), length); + } - /* 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; + // //////////////////////////////////////////////////////////////////////// + // IMemoryBlockRetrievalExtension + // //////////////////////////////////////////////////////////////////////// - // Check for "hexadecimality" - if (expression.startsWith("0x") || expression.startsWith("0X")) { //$NON-NLS-1$//$NON-NLS-2$ - base = 16; - offset = 2; - } + /* + * (non-Javadoc) + * + * @see org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension#getExtendedMemoryBlock(java.lang.String, + * java.lang.Object) + */ + @SuppressWarnings("unchecked") + public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException { - // 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); + // The block start address (supports 64-bit processors) + BigInteger blockAddress; - // All right! We saved a trip to the back-end. - validAddress = true; + /* + * 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 + int base = 10; + int offset = 0; - } catch (NumberFormatException nfexc) { - // OK, expression is not a simple, absolute numeric value; try to resolve as expression - } + // Check for "hexadecimality" + if (expression.startsWith("0x") || expression.startsWith("0X")) { //$NON-NLS-1$//$NON-NLS-2$ + base = 16; + offset = 2; + } + // Check for "octality" + else if (expression.startsWith("0")) { //$NON-NLS-1$ + base = 8; + offset = 1; + } - // 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; - } + // 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 (attempt an expression evaluation) + blockAddress = new BigInteger(expression.substring(offset), base); - /* 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. - */ + } catch (NumberFormatException nfexc) { + // OK, expression is not a simple, absolute numeric value; + // try to resolve as an expression. + // In case of failure, simply return 'null' - return new DsfMemoryBlock(DsfMemoryBlockRetrieval.this, fModelId, expression, address, 0); - } + // Drill for the actual DMC + IDMContext dmc = null; + if (context instanceof IAdaptable) { + dmc = (IDMContext)((IAdaptable)context).getAdapter(IDMContext.class); + } - // //////////////////////////////////////////////////////////////////////// - // Helper functions - // //////////////////////////////////////////////////////////////////////// + if (dmc == null) { + return null; + } + // Update the DMC + fContext = dmc; - // [frch] Code removed until we properly hook the ExpressionService - // [frch] Code saved in lmcfrch-memory-070625.PATCH + // Resolve the expression + blockAddress = resolveMemoryAddress(fContext, expression); + if (blockAddress == null) + return null; + } + + /* + * At this point, we only resolved the requested memory block + * start address and we have no idea of the block's length. + * + * The renderer will provide this information when it calls + * getBytesFromAddress() i.e. after the memory block holder has + * been instantiated. + * + * The down side is that every time we switch renderer, for the + * same memory block, a trip to the target could result. However, + * the memory request cache should save the day. + */ + + return new DsfMemoryBlock(this, fModelId, expression, blockAddress, 0); + } + + // //////////////////////////////////////////////////////////////////////// + // Helper functions + // //////////////////////////////////////////////////////////////////////// + + private BigInteger resolveMemoryAddress(final IDMContext idmContext, final String expression) throws DebugException { + + // Use a Query to "synchronize" the inherently asynchronous downstream calls + Query query = new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + // Lookup for the ExpressionService + final IExpressions expressionService = (IExpressions) fExpressionServiceTracker.getService(); + if (expressionService != null) { + // Create the expression + final IExpressionDMContext expressionDMC = expressionService.createExpression(idmContext, expression); + expressionService.getModelData(expressionDMC, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Evaluate the expression - request HEX since it works in every case + String formatId = IFormattedValues.HEX_FORMAT; + FormattedValueDMContext valueDmc = expressionService.getFormattedValue(expressionDMC, formatId); + expressionService.getModelData( + valueDmc, + new DataRequestMonitor(getExecutor(), null) { + @Override + protected void handleOK() { + // Store the result + FormattedValueDMData data = getData(); + if (data.isValid()) { + String value = data.getFormattedValue().substring(2); // Strip the "0x" + rm.setData(new BigInteger(value, 16)); + } + rm.done(); + } + } + ); + } + }); + } + + } + }; + fExecutor.execute(query); + try { + // The happy case + return query.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + + // The error case + return null; + } } 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 d1ac1282c8f..c38dd7851d0 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 @@ -8,10 +8,12 @@ * Contributors: * Wind River Systems - initial API and implementation * Ericsson Communication - extended the API for IMemoryBlockExtension + * Ericsson Communication - added support for 64 bit processors *******************************************************************************/ package org.eclipse.dd.dsf.debug.service; -import org.eclipse.cdt.core.IAddress; +import java.math.BigInteger; + import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.service.IDsfService; @@ -24,13 +26,26 @@ import org.eclipse.debug.core.model.MemoryByte; */ public interface IMemory extends IDsfService { - /** Writes the given value to the given memory location. */ - public void setMemory(IDMContext ctx, IAddress addr, - int word_size, byte[] buf, int offs, int size, int mode, RequestMonitor requestMonitor); + public class MemoryChangedEvent { + BigInteger fAddress; + public MemoryChangedEvent(BigInteger address) { + fAddress = address; + } + + public BigInteger getAddress() { + return fAddress; + } + } + + /** Reads memory at the given location */ - public void getMemory(IDMContext ctx, IAddress addr, - int word_size, byte[] buf, int offs, int size, int mode, RequestMonitor requestMonitor); + public void getMemory(IDMContext ctx, BigInteger addr, + int word_size, MemoryByte[] buf, int offs, int size, int mode, RequestMonitor rm); + + /** Writes the given value to the given memory location. */ + public void setMemory(IDMContext ctx, BigInteger addr, + int word_size, byte[] buf, int offs, int size, int mode, RequestMonitor rm); /** * Fill target memory with given pattern. @@ -38,25 +53,7 @@ public interface IMemory extends IDsfService { * Parameter 0 of sequent 'done' is assigned with Throwable if * there was an error. */ - public void fillMemory(IDMContext ctx, IAddress addr, - int word_size, byte[] value, int size, int mode, RequestMonitor requestMonitor); + public void fillMemory(IDMContext ctx, BigInteger addr, + int word_size, byte[] value, int size, int mode, RequestMonitor rm); - // //////////////////////////////////////////////////////////////////////// - // 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); - }