diff options
Diffstat (limited to 'dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIMemory.java')
-rw-r--r-- | dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIMemory.java | 1332 |
1 files changed, 667 insertions, 665 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIMemory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIMemory.java index e00d21453f9..52f90903777 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIMemory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIMemory.java @@ -7,7 +7,7 @@ * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 - * + * * Contributors: * Wind River Systems - initial API and implementation * Ericsson AB - expanded from initial stub @@ -76,75 +76,73 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer private static final String READ_MEMORY_BYTES_FEATURE = "data-read-memory-bytes"; //$NON-NLS-1$ //data-read-memory write is deprecated, its description could be ambiguous for e.g. 16 bit addressable systems private static final String DATA_WRITE_MEMORY_16_NOT_SUPPORTED = "data-write-memory with word-size != 1 not supported"; //$NON-NLS-1$ - - public class MemoryChangedEvent extends AbstractDMEvent<IMemoryDMContext> - implements IMemoryChangedEvent - { - private IAddress[] fAddresses; - - public MemoryChangedEvent(IMemoryDMContext context, IAddress[] addresses) { - super(context); - fAddresses = addresses; - } - - @Override - public IAddress[] getAddresses() { - return fAddresses; - } - } + + public class MemoryChangedEvent extends AbstractDMEvent<IMemoryDMContext> implements IMemoryChangedEvent { + private IAddress[] fAddresses; + + public MemoryChangedEvent(IMemoryDMContext context, IAddress[] addresses) { + super(context); + fAddresses = addresses; + } + + @Override + public IAddress[] getAddresses() { + return fAddresses; + } + } // Back-end commands cache private CommandCache fCommandCache; private CommandFactory fCommandFactory; // Map of memory caches - private Map<IMemoryDMContext, MIMemoryCache> fMemoryCaches; - - /** @since 4.2 */ - protected MIMemoryCache getMemoryCache(IMemoryDMContext memoryDMC) { - MIMemoryCache cache = fMemoryCaches.get(memoryDMC); - if (cache == null) { - cache = new MIMemoryCache(); - fMemoryCaches.put(memoryDMC, cache); - } - return cache; - } - - // Whether the -data-read-memory-bytes should be used - // instead of -data-read-memory - private boolean fDataReadMemoryBytes; - + private Map<IMemoryDMContext, MIMemoryCache> fMemoryCaches; + + /** @since 4.2 */ + protected MIMemoryCache getMemoryCache(IMemoryDMContext memoryDMC) { + MIMemoryCache cache = fMemoryCaches.get(memoryDMC); + if (cache == null) { + cache = new MIMemoryCache(); + fMemoryCaches.put(memoryDMC, cache); + } + return cache; + } + + // Whether the -data-read-memory-bytes should be used + // instead of -data-read-memory + private boolean fDataReadMemoryBytes; + /** - * Constructor + * Constructor */ public MIMemory(DsfSession session) { super(session); - } + } - /////////////////////////////////////////////////////////////////////////// - // AbstractDsfService overrides - /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + // AbstractDsfService overrides + /////////////////////////////////////////////////////////////////////////// /* (non-Javadoc) * @see org.eclipse.cdt.dsf.service.AbstractDsfService#initialize(org.eclipse.cdt.dsf.concurrent.RequestMonitor) */ @Override - public void initialize(final RequestMonitor requestMonitor) { - super.initialize(new ImmediateRequestMonitor(requestMonitor) { - @Override - protected void handleSuccess() { - doInitialize(requestMonitor); - } - }); - } - - private void doInitialize(final RequestMonitor requestMonitor) { - IGDBControl commandControl = getServicesTracker().getService(IGDBControl.class); - BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(commandControl, getExecutor(), 2); - - fDataReadMemoryBytes = commandControl.getFeatures().contains(READ_MEMORY_BYTES_FEATURE); - - fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); + public void initialize(final RequestMonitor requestMonitor) { + super.initialize(new ImmediateRequestMonitor(requestMonitor) { + @Override + protected void handleSuccess() { + doInitialize(requestMonitor); + } + }); + } + + private void doInitialize(final RequestMonitor requestMonitor) { + IGDBControl commandControl = getServicesTracker().getService(IGDBControl.class); + BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(commandControl, getExecutor(), 2); + + fDataReadMemoryBytes = commandControl.getFeatures().contains(READ_MEMORY_BYTES_FEATURE); + + fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); // This cache stores the result of a command when received; also, this cache // is manipulated when receiving events. Currently, events are received after @@ -154,223 +152,231 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer // To solve this, we use a bufferedCommandControl that will delay the command // result by two scheduling of the executor. // See bug 280461 - fCommandCache = new CommandCache(getSession(), bufferedCommandControl); - fCommandCache.setContextAvailable(commandControl.getContext(), true); + fCommandCache = new CommandCache(getSession(), bufferedCommandControl); + fCommandCache.setContextAvailable(commandControl.getContext(), true); - register(new String[] { MIMemory.class.getName(), IMemory.class.getName() }, new Hashtable<String, String>()); + register(new String[] { MIMemory.class.getName(), IMemory.class.getName() }, new Hashtable<String, String>()); - fMemoryCaches = new HashMap<IMemoryDMContext, MIMemoryCache>(); + fMemoryCaches = new HashMap<IMemoryDMContext, MIMemoryCache>(); - getSession().addServiceEventListener(this, null); + getSession().addServiceEventListener(this, null); - requestMonitor.done(); - } + requestMonitor.done(); + } - /* (non-Javadoc) - * @see org.eclipse.cdt.dsf.service.AbstractDsfService#shutdown(org.eclipse.cdt.dsf.concurrent.RequestMonitor) - */ - @Override - public void shutdown(final RequestMonitor requestMonitor) { + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.service.AbstractDsfService#shutdown(org.eclipse.cdt.dsf.concurrent.RequestMonitor) + */ + @Override + public void shutdown(final RequestMonitor requestMonitor) { - unregister(); + unregister(); - getSession().removeServiceEventListener(this); + getSession().removeServiceEventListener(this); - super.shutdown(requestMonitor); - } + super.shutdown(requestMonitor); + } - /* (non-Javadoc) - * @see org.eclipse.cdt.dsf.service.AbstractDsfService#getBundleContext() - */ - @Override - protected BundleContext getBundleContext() { - return GdbPlugin.getBundleContext(); - } + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.service.AbstractDsfService#getBundleContext() + */ + @Override + protected BundleContext getBundleContext() { + return GdbPlugin.getBundleContext(); + } - /////////////////////////////////////////////////////////////////////////// - // IMemory - /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + // IMemory + /////////////////////////////////////////////////////////////////////////// - /* (non-Javadoc) - * @see org.eclipse.cdt.dsf.debug.service.IMemory#getMemory(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor) - */ + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.service.IMemory#getMemory(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor) + */ @Override - public void getMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, - int wordSize, int wordCount, DataRequestMonitor<MemoryByte[]> drm) - { - if (memoryDMC == null) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); - drm.done(); - return; - } - - if (wordSize < 1) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Word size not supported (< 1)", null)); //$NON-NLS-1$ - drm.done(); - return; - } - - if (wordCount < 0) { - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Invalid word count (< 0)", null)); //$NON-NLS-1$ - drm.done(); - return; - } - - getMemoryCache(memoryDMC).getMemory(memoryDMC, address.add(offset), wordSize, wordCount, drm); + public void getMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, int wordSize, int wordCount, + DataRequestMonitor<MemoryByte[]> drm) { + if (memoryDMC == null) { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + drm.done(); + return; + } + + if (wordSize < 1) { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Word size not supported (< 1)", //$NON-NLS-1$ + null)); + drm.done(); + return; + } + + if (wordCount < 0) { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, + "Invalid word count (< 0)", null)); //$NON-NLS-1$ + drm.done(); + return; + } + + getMemoryCache(memoryDMC).getMemory(memoryDMC, address.add(offset), wordSize, wordCount, drm); } - /* (non-Javadoc) - * @see org.eclipse.cdt.dsf.debug.service.IMemory#setMemory(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, byte[], org.eclipse.cdt.dsf.concurrent.RequestMonitor) - */ + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.service.IMemory#setMemory(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, byte[], org.eclipse.cdt.dsf.concurrent.RequestMonitor) + */ @Override - public void setMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, - int wordSize, int wordCount, byte[] buffer, RequestMonitor rm) - { - if (memoryDMC == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); - rm.done(); - return; - } - - if (wordSize < 1) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Word size not supported (< 1)", null)); //$NON-NLS-1$ - rm.done(); - return; - } - - if (wordCount < 0) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Invalid word count (< 0)", null)); //$NON-NLS-1$ - rm.done(); - return; - } - - if (buffer.length < wordCount * wordSize) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Buffer too short", null)); //$NON-NLS-1$ - rm.done(); - return; - } - - getMemoryCache(memoryDMC).setMemory(memoryDMC, address, offset, wordSize, wordCount, buffer, rm); - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.dsf.debug.service.IMemory#fillMemory(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, byte[], org.eclipse.cdt.dsf.concurrent.RequestMonitor) - */ + public void setMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, int wordSize, int wordCount, + byte[] buffer, RequestMonitor rm) { + if (memoryDMC == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + rm.done(); + return; + } + + if (wordSize < 1) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Word size not supported (< 1)", //$NON-NLS-1$ + null)); + rm.done(); + return; + } + + if (wordCount < 0) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, + "Invalid word count (< 0)", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + if (buffer.length < wordCount * wordSize) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, + "Buffer too short", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + getMemoryCache(memoryDMC).setMemory(memoryDMC, address, offset, wordSize, wordCount, buffer, rm); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.service.IMemory#fillMemory(org.eclipse.cdt.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, byte[], org.eclipse.cdt.dsf.concurrent.RequestMonitor) + */ @Override - public void fillMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, - int wordSize, int count, byte[] pattern, RequestMonitor rm) - { - if (memoryDMC == null) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); - rm.done(); - return; - } - - if (wordSize < 1) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Word size not supported (< 1)", null)); //$NON-NLS-1$ - rm.done(); - return; - } - - if (count < 0) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Invalid repeat count (< 0)", null)); //$NON-NLS-1$ - rm.done(); - return; - } - - if (pattern.length < 1) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Empty pattern", null)); //$NON-NLS-1$ - rm.done(); - return; - } - - // Create an aggregate buffer so we can write in 1 shot - int length = pattern.length; - byte[] buffer = new byte[count * length]; - for (int i = 0; i < count; i++) { - System.arraycopy(pattern, 0, buffer, i * length, length); - } - - int word_count = buffer.length / wordSize; - if (buffer.length % wordSize != 0) { - word_count ++; - } - - // All is clear: go for it - getMemoryCache(memoryDMC).setMemory(memoryDMC, address, offset, wordSize, word_count, buffer, rm); - } - - /////////////////////////////////////////////////////////////////////// - // Back-end functions - /////////////////////////////////////////////////////////////////////// - - /** - * @param memoryDMC - * @param address - * @param offset - * @param wordSize - * @param wordCount in addressable units - * @param drm - * - * @since 1.1 - */ - protected void readMemoryBlock(IDMContext dmc, IAddress address, final long offset, - final int wordSize, final int wordCount, final DataRequestMonitor<MemoryByte[]> drm) - { - if (fDataReadMemoryBytes) { - fCommandCache.execute( - fCommandFactory.createMIDataReadMemoryBytes(dmc, address.toString(), offset, wordCount, wordSize), - new DataRequestMonitor<MIDataReadMemoryBytesInfo>(getExecutor(), drm) { - @Override - protected void handleSuccess() { - // Retrieve the memory block - drm.setData(getData().getMIMemoryBlock()); - drm.done(); - } - @Override - protected void handleFailure() { - drm.setData(createInvalidBlock(wordSize * wordCount)); - drm.done(); - } - }); - } else { - if (wordSize != 1) { - //The word-size is specified within the resulting command data-read-memory - //The word-size is defined in bytes although in the MI interface it's not clear if the meaning is - //octets or system dependent bytes (minimum addressable memory). - //As this command is deprecated there is no good reason to augment the support for word sizes != 1 - drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, DATA_WRITE_MEMORY_16_NOT_SUPPORTED, null)); - drm.done(); - return; - } - - /* To simplify the parsing of the MI result, we request the output to - * be on 1 row of [count] columns, no char interpretation. - */ - int mode = MIFormat.HEXADECIMAL; - int nbRows = 1; - int nbCols = wordCount; - Character asChar = null; - - fCommandCache.execute( - fCommandFactory.createMIDataReadMemory(dmc, offset, address.toString(), mode, wordSize, nbRows, nbCols, asChar), - new DataRequestMonitor<MIDataReadMemoryInfo>(getExecutor(), drm) { - @Override - protected void handleSuccess() { - // Retrieve the memory block - drm.setData(getData().getMIMemoryBlock()); - drm.done(); - } - @Override - protected void handleFailure() { - drm.setData(createInvalidBlock(wordSize * wordCount)); - drm.done(); - } - } - ); - } - } - + public void fillMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, int wordSize, int count, + byte[] pattern, RequestMonitor rm) { + if (memoryDMC == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + rm.done(); + return; + } + + if (wordSize < 1) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Word size not supported (< 1)", //$NON-NLS-1$ + null)); + rm.done(); + return; + } + + if (count < 0) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, + "Invalid repeat count (< 0)", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + if (pattern.length < 1) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, + "Empty pattern", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create an aggregate buffer so we can write in 1 shot + int length = pattern.length; + byte[] buffer = new byte[count * length]; + for (int i = 0; i < count; i++) { + System.arraycopy(pattern, 0, buffer, i * length, length); + } + + int word_count = buffer.length / wordSize; + if (buffer.length % wordSize != 0) { + word_count++; + } + + // All is clear: go for it + getMemoryCache(memoryDMC).setMemory(memoryDMC, address, offset, wordSize, word_count, buffer, rm); + } + + /////////////////////////////////////////////////////////////////////// + // Back-end functions + /////////////////////////////////////////////////////////////////////// + + /** + * @param memoryDMC + * @param address + * @param offset + * @param wordSize + * @param wordCount in addressable units + * @param drm + * + * @since 1.1 + */ + protected void readMemoryBlock(IDMContext dmc, IAddress address, final long offset, final int wordSize, + final int wordCount, final DataRequestMonitor<MemoryByte[]> drm) { + if (fDataReadMemoryBytes) { + fCommandCache.execute( + fCommandFactory.createMIDataReadMemoryBytes(dmc, address.toString(), offset, wordCount, wordSize), + new DataRequestMonitor<MIDataReadMemoryBytesInfo>(getExecutor(), drm) { + @Override + protected void handleSuccess() { + // Retrieve the memory block + drm.setData(getData().getMIMemoryBlock()); + drm.done(); + } + + @Override + protected void handleFailure() { + drm.setData(createInvalidBlock(wordSize * wordCount)); + drm.done(); + } + }); + } else { + if (wordSize != 1) { + //The word-size is specified within the resulting command data-read-memory + //The word-size is defined in bytes although in the MI interface it's not clear if the meaning is + //octets or system dependent bytes (minimum addressable memory). + //As this command is deprecated there is no good reason to augment the support for word sizes != 1 + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, + DATA_WRITE_MEMORY_16_NOT_SUPPORTED, null)); + drm.done(); + return; + } + + /* To simplify the parsing of the MI result, we request the output to + * be on 1 row of [count] columns, no char interpretation. + */ + int mode = MIFormat.HEXADECIMAL; + int nbRows = 1; + int nbCols = wordCount; + Character asChar = null; + + fCommandCache + .execute( + fCommandFactory.createMIDataReadMemory(dmc, offset, address.toString(), mode, wordSize, + nbRows, nbCols, asChar), + new DataRequestMonitor<MIDataReadMemoryInfo>(getExecutor(), drm) { + @Override + protected void handleSuccess() { + // Retrieve the memory block + drm.setData(getData().getMIMemoryBlock()); + drm.done(); + } + + @Override + protected void handleFailure() { + drm.setData(createInvalidBlock(wordSize * wordCount)); + drm.done(); + } + }); + } + } + private MemoryByte[] createInvalidBlock(int size) { // Bug234289: If memory read fails, return a block marked as invalid MemoryByte[] block = new MemoryByte[size]; @@ -380,139 +386,140 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer return block; } - /** - * @param memoryDMC - * @param address - * @param offset - * @param wordSize - * @param wordCount in addressable units - * @param buffer - * @param rm - * - * @since 1.1 - */ - protected void writeMemoryBlock(final IDMContext dmc, final IAddress address, final long offset, - final int wordSize, final int wordCount, final byte[] buffer, final RequestMonitor rm) - { - if (fDataReadMemoryBytes) { - // Use -data-write-memory-bytes for performance, - fCommandCache.execute( - fCommandFactory.createMIDataWriteMemoryBytes(dmc, address.add(offset).toString(), - (buffer.length == wordCount*wordSize) ? buffer : Arrays.copyOf(buffer, wordCount*wordSize)), - new DataRequestMonitor<MIInfo>(getExecutor(), rm) - ); - } else { - if (wordSize != 1) { - //The word-size is specified within the resulting command data-write-memory - //The word-size is defined in bytes although in the MI interface it's not clear if the meaning is - //octets or system dependent bytes (minimum addressable memory). - //As this command is deprecated there is no good reason to augment the support for word sizes != 1 - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, DATA_WRITE_MEMORY_16_NOT_SUPPORTED, null)); - rm.done(); - return; - } - - // Each byte is written individually (GDB power...) - // so we need to keep track of the count - final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), rm); - countingRM.setDoneCount(wordCount); - - // We will format the individual bytes in decimal - int format = MIFormat.DECIMAL; - String baseAddress = address.toString(); - - // Issue an MI request for each byte to write - for (int i = 0; i < wordCount; i++) { - String value = Byte.toString(buffer[i]); - fCommandCache.execute( - fCommandFactory.createMIDataWriteMemory(dmc, offset + i, baseAddress, format, wordSize, value), - new DataRequestMonitor<MIDataWriteMemoryInfo>(getExecutor(), countingRM) - ); - } - } - } - - ////////////////////////////////////////////////////////////////////////// - // Event handlers - ////////////////////////////////////////////////////////////////////////// - @DsfServiceEventHandler + /** + * @param memoryDMC + * @param address + * @param offset + * @param wordSize + * @param wordCount in addressable units + * @param buffer + * @param rm + * + * @since 1.1 + */ + protected void writeMemoryBlock(final IDMContext dmc, final IAddress address, final long offset, final int wordSize, + final int wordCount, final byte[] buffer, final RequestMonitor rm) { + if (fDataReadMemoryBytes) { + // Use -data-write-memory-bytes for performance, + fCommandCache.execute( + fCommandFactory.createMIDataWriteMemoryBytes(dmc, address.add(offset).toString(), + (buffer.length == wordCount * wordSize) ? buffer + : Arrays.copyOf(buffer, wordCount * wordSize)), + new DataRequestMonitor<MIInfo>(getExecutor(), rm)); + } else { + if (wordSize != 1) { + //The word-size is specified within the resulting command data-write-memory + //The word-size is defined in bytes although in the MI interface it's not clear if the meaning is + //octets or system dependent bytes (minimum addressable memory). + //As this command is deprecated there is no good reason to augment the support for word sizes != 1 + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, + DATA_WRITE_MEMORY_16_NOT_SUPPORTED, null)); + rm.done(); + return; + } + + // Each byte is written individually (GDB power...) + // so we need to keep track of the count + final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), rm); + countingRM.setDoneCount(wordCount); + + // We will format the individual bytes in decimal + int format = MIFormat.DECIMAL; + String baseAddress = address.toString(); + + // Issue an MI request for each byte to write + for (int i = 0; i < wordCount; i++) { + String value = Byte.toString(buffer[i]); + fCommandCache.execute( + fCommandFactory.createMIDataWriteMemory(dmc, offset + i, baseAddress, format, wordSize, value), + new DataRequestMonitor<MIDataWriteMemoryInfo>(getExecutor(), countingRM)); + } + } + } + + ////////////////////////////////////////////////////////////////////////// + // Event handlers + ////////////////////////////////////////////////////////////////////////// + @DsfServiceEventHandler public void eventDispatched(IResumedDMEvent e) { - if (e instanceof IContainerResumedDMEvent) { - fCommandCache.setContextAvailable(e.getDMContext(), false); - } - - if (e.getReason() != StateChangeReason.STEP) { - IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(e.getDMContext(), IMemoryDMContext.class); - // It is the memory context we want to clear, not only the context that resumed. The resumed context - // is probably a thread but that running thread could have changed any memory within the memory - // context. - if (memoryDMC != null) { - fCommandCache.reset(memoryDMC); - - memoryCacheReset(memoryDMC); - } - } + if (e instanceof IContainerResumedDMEvent) { + fCommandCache.setContextAvailable(e.getDMContext(), false); + } + + if (e.getReason() != StateChangeReason.STEP) { + IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(e.getDMContext(), IMemoryDMContext.class); + // It is the memory context we want to clear, not only the context that resumed. The resumed context + // is probably a thread but that running thread could have changed any memory within the memory + // context. + if (memoryDMC != null) { + fCommandCache.reset(memoryDMC); + + memoryCacheReset(memoryDMC); + } + } } - - @DsfServiceEventHandler + + @DsfServiceEventHandler public void eventDispatched(ISuspendedDMEvent e) { - if (e instanceof IContainerSuspendedDMEvent) { - fCommandCache.setContextAvailable(e.getDMContext(), true); - } - - IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(e.getDMContext(), IMemoryDMContext.class); - // It is the memory context we want to clear, not only the context that stopped. The stopped context - // is probably a thread but that thread that ran could have changed any memory within the memory - // context. - if (memoryDMC != null) { - fCommandCache.reset(memoryDMC); - - memoryCacheReset(memoryDMC); - } + if (e instanceof IContainerSuspendedDMEvent) { + fCommandCache.setContextAvailable(e.getDMContext(), true); + } + + IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(e.getDMContext(), IMemoryDMContext.class); + // It is the memory context we want to clear, not only the context that stopped. The stopped context + // is probably a thread but that thread that ran could have changed any memory within the memory + // context. + if (memoryDMC != null) { + fCommandCache.reset(memoryDMC); + + memoryCacheReset(memoryDMC); + } } /** * @deprecated Replaced by the generic {@link #eventDispatched(IExpressionChangedDMEvent)} */ - @Deprecated + @Deprecated public void eventDispatched(ExpressionChangedEvent e) { - } + } - /** - * @noreference This method is not intended to be referenced by clients. - * @since 4.2 - */ - @DsfServiceEventHandler - public void eventDispatched(IExpressionChangedDMEvent e) { + /** + * @noreference This method is not intended to be referenced by clients. + * @since 4.2 + */ + @DsfServiceEventHandler + public void eventDispatched(IExpressionChangedDMEvent e) { - // Get the context and expression service handle - final IExpressionDMContext context = e.getDMContext(); + // Get the context and expression service handle + final IExpressionDMContext context = e.getDMContext(); IExpressions expressionService = getServicesTracker().getService(IExpressions.class); // Get the variable information and update the corresponding memory locations if (expressionService != null) { expressionService.getExpressionAddressData(context, - new DataRequestMonitor<IExpressionDMAddress>(getExecutor(), null) { - @Override - protected void handleSuccess() { - // Figure out which memory area was modified - IExpressionDMAddress expression = getData(); - IAddress expAddress = expression.getAddress(); - if (expAddress != IExpressions.IExpressionDMLocation.INVALID_ADDRESS) { - final int count = expression.getSize(); - final Addr64 address; - if (expAddress instanceof Addr64) { - address = (Addr64) expAddress; - } else { - address = new Addr64(expAddress.getValue()); + new DataRequestMonitor<IExpressionDMAddress>(getExecutor(), null) { + @Override + protected void handleSuccess() { + // Figure out which memory area was modified + IExpressionDMAddress expression = getData(); + IAddress expAddress = expression.getAddress(); + if (expAddress != IExpressions.IExpressionDMLocation.INVALID_ADDRESS) { + final int count = expression.getSize(); + final Addr64 address; + if (expAddress instanceof Addr64) { + address = (Addr64) expAddress; + } else { + address = new Addr64(expAddress.getValue()); + } + + final IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, + IMemoryDMContext.class); + getMemoryCache(memoryDMC).refreshMemory(memoryDMC, address, 0, + getAddressableSize(memoryDMC), count, true, + new RequestMonitor(getExecutor(), null)); } - - final IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, IMemoryDMContext.class); - getMemoryCache(memoryDMC).refreshMemory(memoryDMC, address, 0, getAddressableSize(memoryDMC), count, true, - new RequestMonitor(getExecutor(), null)); } - } - }); + }); } } @@ -523,18 +530,19 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer protected int getAddressableSize(IMemoryDMContext context) { return 1; } - + /////////////////////////////////////////////////////////////////////////// // SortedLinkedlist /////////////////////////////////////////////////////////////////////////// // This class is really the equivalent of a C struct (old habits die hard...) - // For simplicity, everything is public. - private static class MemoryBlock { + // For simplicity, everything is public. + private static class MemoryBlock { public IAddress fAddress; public long fLengthInAddressableUnits; public long fLengthInOctets; public MemoryByte[] fBlock; + public MemoryBlock(IAddress address, long lengthInOctets, long lengthInAddressableUnits, MemoryByte[] block) { // A memory block is expected to be populated with the contents of a defined range of addresses // therefore the number of octets shall be divisible by the number of addresses @@ -546,8 +554,8 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer } } - // Address-ordered data structure to cache the memory blocks. - // Contiguous blocks are merged if possible. + // Address-ordered data structure to cache the memory blocks. + // Contiguous blocks are merged if possible. @SuppressWarnings("serial") private static class SortedMemoryBlockList extends LinkedList<MemoryBlock> { @@ -579,7 +587,7 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer } } - // Put at the end of the list and merge if necessary + // Put at the end of the list and merge if necessary addLast(block); compact(size() - 1); return true; @@ -589,7 +597,7 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer // Note: Merge is not performed if resulting block size would exceed MAXINT private void compact(int index) { - MemoryBlock newBlock = get(index); + MemoryBlock newBlock = get(index); // Case where the block is to be merged with the previous block if (index > 0) { @@ -597,12 +605,15 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer IAddress endOfPreviousBlock = prevBlock.fAddress.add(prevBlock.fLengthInAddressableUnits); if (endOfPreviousBlock.distanceTo(newBlock.fAddress).longValue() == 0) { long newLengthInOctets = prevBlock.fLengthInOctets + newBlock.fLengthInOctets; - long newLengthInAddressableUnits = prevBlock.fLengthInAddressableUnits + newBlock.fLengthInAddressableUnits; + long newLengthInAddressableUnits = prevBlock.fLengthInAddressableUnits + + newBlock.fLengthInAddressableUnits; if (newLengthInOctets <= Integer.MAX_VALUE) { - MemoryByte[] block = new MemoryByte[(int) newLengthInOctets] ; + MemoryByte[] block = new MemoryByte[(int) newLengthInOctets]; System.arraycopy(prevBlock.fBlock, 0, block, 0, (int) prevBlock.fLengthInOctets); - System.arraycopy(newBlock.fBlock, 0, block, (int) prevBlock.fLengthInOctets, (int) newBlock.fLengthInOctets); - newBlock = new MemoryBlock(prevBlock.fAddress, newLengthInOctets, newLengthInAddressableUnits, block); + System.arraycopy(newBlock.fBlock, 0, block, (int) prevBlock.fLengthInOctets, + (int) newBlock.fLengthInOctets); + newBlock = new MemoryBlock(prevBlock.fAddress, newLengthInOctets, newLengthInAddressableUnits, + block); remove(index); index -= 1; set(index, newBlock); @@ -619,9 +630,10 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer long newLength = newBlock.fLengthInOctets + nextBlock.fLengthInOctets; long newAddressesLength = newBlock.fLengthInAddressableUnits + nextBlock.fLengthInAddressableUnits; if (newLength <= Integer.MAX_VALUE) { - MemoryByte[] block = new MemoryByte[(int) newLength] ; + MemoryByte[] block = new MemoryByte[(int) newLength]; System.arraycopy(newBlock.fBlock, 0, block, 0, (int) newBlock.fLengthInOctets); - System.arraycopy(nextBlock.fBlock, 0, block, (int) newBlock.fLengthInOctets, (int) nextBlock.fLengthInOctets); + System.arraycopy(nextBlock.fBlock, 0, block, (int) newBlock.fLengthInOctets, + (int) nextBlock.fLengthInOctets); newBlock = new MemoryBlock(newBlock.fAddress, newLength, newAddressesLength, block); set(index, newBlock); remove(index + 1); @@ -641,74 +653,74 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer private SortedMemoryBlockList fMemoryBlockList; public MIMemoryCache() { - // Create the memory block cache - fMemoryBlockList = new SortedMemoryBlockList(); + // Create the memory block cache + fMemoryBlockList = new SortedMemoryBlockList(); } public void reset() { - // Clear the memory cache - fMemoryBlockList.clear(); + // Clear the memory cache + fMemoryBlockList.clear(); } - /** - * This function walks the address-sorted memory block list to identify - * the 'missing' blocks (i.e. the holes) that need to be fetched on the target. - * - * The idea is fairly simple but an illustration could perhaps help. - * Assume the cache holds a number of cached memory blocks with gaps i.e. - * there is un-cached memory areas between blocks A, B and C: - * - * +---------+ +---------+ +---------+ - * + A + + B + + C + - * +---------+ +---------+ +---------+ - * : : : : : : - * [a] : : [b] : : [c] : : [d] - * : : : : : : - * [e---+--] : [f--+---------+--] : : - * [g---+---------+------+---------+------+---------+----] - * : : : : : : - * : [h] : : [i----+--] : : - * - * - * We have the following cases to consider.The requested block [a-i] either: - * - * [1] Fits entirely before A, in one of the gaps, or after C - * with no overlap and no contiguousness (e.g. [a], [b], [c] and [d]) - * -> Add the requested block to the list of blocks to fetch - * - * [2] Starts before an existing block but overlaps part of it, possibly - * spilling in the gap following the cached block (e.g. [e], [f] and [g]) - * -> Determine the length of the missing part (< count) - * -> Add a request to fill the gap before the existing block - * -> Update the requested block for the next iteration: - * - Start address to point just after the end of the cached block - * - Count reduced by cached block length (possibly becoming negative, e.g. [e]) - * At this point, the updated requested block starts just beyond the cached block - * for the next iteration. - * - * [3] Starts at or into an existing block and overlaps part of it ([h] and [i]) - * -> Update the requested block for the next iteration: - * - Start address to point just after the end of the cached block - * - Count reduced by length to end of cached block (possibly becoming negative, e.g. [h]) - * At this point, the updated requested block starts just beyond the cached block - * for the next iteration. - * - * We iterate over the cached blocks list until there is no entry left or until - * the remaining requested block count is <= 0, meaning the result list contains - * only the sub-blocks needed to fill the gap(s), if any. - * - * (As is often the case, it takes much more typing to explain it than to just do it :-) - * - * What is missing is a parameter that indicates the minimal block size that is worth fetching. - * This is target-specific and straight in the realm of the coalescing function... - * - * @param reqBlockStart The address of the requested block - * @param count Its length - * @return A list of the sub-blocks to fetch in order to fill enough gaps in the memory cache - * to service the request - */ - private List<MemoryBlock> getListOfMissingBlocks(IAddress reqBlockStart, int wordCount, int wordSize) { - int octetCount = wordCount * wordSize; + /** + * This function walks the address-sorted memory block list to identify + * the 'missing' blocks (i.e. the holes) that need to be fetched on the target. + * + * The idea is fairly simple but an illustration could perhaps help. + * Assume the cache holds a number of cached memory blocks with gaps i.e. + * there is un-cached memory areas between blocks A, B and C: + * + * +---------+ +---------+ +---------+ + * + A + + B + + C + + * +---------+ +---------+ +---------+ + * : : : : : : + * [a] : : [b] : : [c] : : [d] + * : : : : : : + * [e---+--] : [f--+---------+--] : : + * [g---+---------+------+---------+------+---------+----] + * : : : : : : + * : [h] : : [i----+--] : : + * + * + * We have the following cases to consider.The requested block [a-i] either: + * + * [1] Fits entirely before A, in one of the gaps, or after C + * with no overlap and no contiguousness (e.g. [a], [b], [c] and [d]) + * -> Add the requested block to the list of blocks to fetch + * + * [2] Starts before an existing block but overlaps part of it, possibly + * spilling in the gap following the cached block (e.g. [e], [f] and [g]) + * -> Determine the length of the missing part (< count) + * -> Add a request to fill the gap before the existing block + * -> Update the requested block for the next iteration: + * - Start address to point just after the end of the cached block + * - Count reduced by cached block length (possibly becoming negative, e.g. [e]) + * At this point, the updated requested block starts just beyond the cached block + * for the next iteration. + * + * [3] Starts at or into an existing block and overlaps part of it ([h] and [i]) + * -> Update the requested block for the next iteration: + * - Start address to point just after the end of the cached block + * - Count reduced by length to end of cached block (possibly becoming negative, e.g. [h]) + * At this point, the updated requested block starts just beyond the cached block + * for the next iteration. + * + * We iterate over the cached blocks list until there is no entry left or until + * the remaining requested block count is <= 0, meaning the result list contains + * only the sub-blocks needed to fill the gap(s), if any. + * + * (As is often the case, it takes much more typing to explain it than to just do it :-) + * + * What is missing is a parameter that indicates the minimal block size that is worth fetching. + * This is target-specific and straight in the realm of the coalescing function... + * + * @param reqBlockStart The address of the requested block + * @param count Its length + * @return A list of the sub-blocks to fetch in order to fill enough gaps in the memory cache + * to service the request + */ + private List<MemoryBlock> getListOfMissingBlocks(IAddress reqBlockStart, int wordCount, int wordSize) { + int octetCount = wordCount * wordSize; LinkedList<MemoryBlock> list = new LinkedList<MemoryBlock>(); ListIterator<MemoryBlock> it = fMemoryBlockList.listIterator(); @@ -717,15 +729,17 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer while (it.hasNext() && octetCount > 0) { MemoryBlock cachedBlock = it.next(); IAddress cachedBlockStart = cachedBlock.fAddress; - IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLengthInAddressableUnits); + IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLengthInAddressableUnits); // Case where we miss a block before the cached block if (reqBlockStart.distanceTo(cachedBlockStart).longValue() >= 0) { - int lengthInOctets = (int) Math.min(reqBlockStart.distanceTo(cachedBlockStart).longValue()*wordSize, octetCount); + int lengthInOctets = (int) Math + .min(reqBlockStart.distanceTo(cachedBlockStart).longValue() * wordSize, octetCount); // If both blocks start at the same location, no need to create a new cached block if (lengthInOctets > 0) { int lengthInAddressableUnits = lengthInOctets / wordSize; - MemoryBlock newBlock = new MemoryBlock(reqBlockStart, lengthInOctets, lengthInAddressableUnits, new MemoryByte[0]); + MemoryBlock newBlock = new MemoryBlock(reqBlockStart, lengthInOctets, lengthInAddressableUnits, + new MemoryByte[0]); list.add(newBlock); } // Adjust request block start and length for the next iteration @@ -735,11 +749,10 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer // Case where the requested block starts somewhere in the cached block else if (cachedBlockStart.distanceTo(reqBlockStart).longValue() > 0 - && reqBlockStart.distanceTo(cachedBlockEnd).longValue() >= 0) - { + && reqBlockStart.distanceTo(cachedBlockEnd).longValue() >= 0) { // Start of the requested block already in cache // Adjust request block start and length for the next iteration - octetCount -= reqBlockStart.distanceTo(cachedBlockEnd).longValue()*wordSize; + octetCount -= reqBlockStart.distanceTo(cachedBlockEnd).longValue() * wordSize; reqBlockStart = cachedBlockEnd; } } @@ -750,39 +763,39 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer MemoryBlock newBlock = new MemoryBlock(reqBlockStart, octetCount, addressesLength, new MemoryByte[0]); list.add(newBlock); } - + return list; } - /** - * This function walks the address-sorted memory block list to get the - * cached memory bytes (possibly from multiple contiguous blocks). - * This function is called *after* the missing blocks have been read from - * the back end i.e. the requested memory is all cached. - * - * Again, this is fairly simple. As we loop over the address-ordered list, - * There are really only 2 cases: - * - * [1] The requested block fits entirely in the cached block ([a] or [b]) - * [2] The requested block starts in a cached block and ends in the - * following (contiguous) one ([c]) in which case it is treated - * as 2 contiguous requests ([c'] and [c"]) - * - * +--------------+--------------+ - * + A + B + - * +--------------+--------------+ - * : [a----] : [b-----] : - * : : : - * : [c-----+------] : - * : [c'---]+[c"---] : + /** + * This function walks the address-sorted memory block list to get the + * cached memory bytes (possibly from multiple contiguous blocks). + * This function is called *after* the missing blocks have been read from + * the back end i.e. the requested memory is all cached. + * + * Again, this is fairly simple. As we loop over the address-ordered list, + * There are really only 2 cases: * - * @param reqBlockStart The address of the requested block - * @param count Its length - * @return The cached memory content - */ - private MemoryByte[] getMemoryBlockFromCache(IAddress reqBlockStart, int wordCount, int wordSize) { - int count = wordCount * wordSize; - + * [1] The requested block fits entirely in the cached block ([a] or [b]) + * [2] The requested block starts in a cached block and ends in the + * following (contiguous) one ([c]) in which case it is treated + * as 2 contiguous requests ([c'] and [c"]) + * + * +--------------+--------------+ + * + A + B + + * +--------------+--------------+ + * : [a----] : [b-----] : + * : : : + * : [c-----+------] : + * : [c'---]+[c"---] : + * + * @param reqBlockStart The address of the requested block + * @param count Its length + * @return The cached memory content + */ + private MemoryByte[] getMemoryBlockFromCache(IAddress reqBlockStart, int wordCount, int wordSize) { + int count = wordCount * wordSize; + IAddress reqBlockEnd = reqBlockStart.add(wordCount); MemoryByte[] resultBlock = new MemoryByte[count]; ListIterator<MemoryBlock> iter = fMemoryBlockList.listIterator(); @@ -790,41 +803,38 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer while (iter.hasNext()) { MemoryBlock cachedBlock = iter.next(); IAddress cachedBlockStart = cachedBlock.fAddress; - IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLengthInAddressableUnits); + IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLengthInAddressableUnits); - // Case where the cached block overlaps completely the requested memory block + // Case where the cached block overlaps completely the requested memory block if (cachedBlockStart.distanceTo(reqBlockStart).longValue() >= 0 - && reqBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) - { + && reqBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) { int pos = (int) cachedBlockStart.distanceTo(reqBlockStart).longValue() * wordSize; System.arraycopy(cachedBlock.fBlock, pos, resultBlock, 0, count); } - - // Case where the beginning of the cached block is within the requested memory block + + // Case where the beginning of the cached block is within the requested memory block else if (reqBlockStart.distanceTo(cachedBlockStart).longValue() >= 0 - && cachedBlockStart.distanceTo(reqBlockEnd).longValue() > 0) - { + && cachedBlockStart.distanceTo(reqBlockEnd).longValue() > 0) { int pos = (int) reqBlockStart.distanceTo(cachedBlockStart).longValue() * wordSize; int length = (int) Math.min(cachedBlock.fLengthInOctets, count - pos); System.arraycopy(cachedBlock.fBlock, 0, resultBlock, pos, length); } - - // Case where the end of the cached block is within the requested memory block + + // Case where the end of the cached block is within the requested memory block else if (cachedBlockStart.distanceTo(reqBlockStart).longValue() >= 0 - && reqBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) - { + && reqBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) { int pos = (int) cachedBlockStart.distanceTo(reqBlockStart).longValue() * wordSize; int length = (int) Math.min(cachedBlock.fLengthInOctets - pos, count); System.arraycopy(cachedBlock.fBlock, pos, resultBlock, 0, length); } - } + } return resultBlock; } /** - * This function walks the address-sorted memory block list and updates - * the content with the actual memory just read from the target. - * + * This function walks the address-sorted memory block list and updates + * the content with the actual memory just read from the target. + * * @param modBlockStart * @param wordCount - Number of addressable units * @param modBlock @@ -838,211 +848,203 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer while (iter.hasNext()) { MemoryBlock cachedBlock = iter.next(); IAddress cachedBlockStart = cachedBlock.fAddress; - IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLengthInAddressableUnits); - + IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLengthInAddressableUnits); + // For now, we only bother to update bytes already cached. // Note: In a better implementation (v1.1), we would augment - // the cache with the missing memory blocks since we went + // the cache with the missing memory blocks since we went // through the pains of reading them in the first place. // (this is left as an exercise to the reader :-) - // Case where the modified block is completely included in the cached block + // Case where the modified block is completely included in the cached block if (cachedBlockStart.distanceTo(modBlockStart).longValue() >= 0 - && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) - { + && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) { int pos = (int) cachedBlockStart.distanceTo(modBlockStart).longValue() * wordSize; System.arraycopy(modBlock, 0, cachedBlock.fBlock, pos, count); } - + // Case where the cached block is completely included in the modified block else if (modBlockStart.distanceTo(cachedBlockStart).longValue() >= 0 - && cachedBlockEnd.distanceTo(modBlockEnd).longValue() >= 0) - { + && cachedBlockEnd.distanceTo(modBlockEnd).longValue() >= 0) { int pos = (int) modBlockStart.distanceTo(cachedBlockStart).longValue() * wordSize; System.arraycopy(modBlock, pos, cachedBlock.fBlock, 0, (int) cachedBlock.fLengthInOctets); } - // Case where the beginning of the modified block is within the cached block + // Case where the beginning of the modified block is within the cached block else if (cachedBlockStart.distanceTo(modBlockStart).longValue() >= 0 - && modBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) - { + && modBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) { int pos = (int) cachedBlockStart.distanceTo(modBlockStart).longValue() * wordSize; int length = (int) modBlockStart.distanceTo(cachedBlockEnd).longValue() * wordSize; System.arraycopy(modBlock, 0, cachedBlock.fBlock, pos, length); } - - // Case where the end of the modified block is within the cached block + + // Case where the end of the modified block is within the cached block else if (cachedBlockStart.distanceTo(modBlockEnd).longValue() > 0 - && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) - { + && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) { int pos = (int) modBlockStart.distanceTo(cachedBlockStart).longValue() * wordSize; int length = (int) cachedBlockStart.distanceTo(modBlockEnd).longValue() * wordSize; System.arraycopy(modBlock, pos, cachedBlock.fBlock, 0, length); } - } + } return; } - /** + /** * @param memoryDMC - * @param address the memory block address (on the target) - * @param wordSize the size, in bytes, of an addressable item - * @param wordCount the number of addressable units to read - * @param drm the asynchronous data request monitor - */ - public void getMemory(IMemoryDMContext memoryDMC, final IAddress address, final int wordSize, - final int wordCount, final DataRequestMonitor<MemoryByte[]> drm) - { - // Determine the number of read requests to issue - List<MemoryBlock> missingBlocks = getListOfMissingBlocks(address, wordCount, wordSize); - int numberOfRequests = missingBlocks.size(); - - // A read request will be issued for each block needed - // so we need to keep track of the count - final CountingRequestMonitor countingRM = - new CountingRequestMonitor(getExecutor(), drm) { - @Override - protected void handleSuccess() { - // We received everything so read the result from the memory cache - drm.setData(getMemoryBlockFromCache(address, wordCount, wordSize)); - drm.done(); - } - }; - countingRM.setDoneCount(numberOfRequests); - - // Issue the read requests - for (int i = 0; i < numberOfRequests; i++) { - MemoryBlock block = missingBlocks.get(i); - final IAddress startAddress = block.fAddress; - final int length = (int) block.fLengthInAddressableUnits; - readMemoryBlock(memoryDMC, startAddress, 0, wordSize, length, - new DataRequestMonitor<MemoryByte[]>(getSession().getExecutor(), drm) { - @Override - protected void handleSuccess() { - MemoryByte[] block = getData(); - int lenghtInaddressableUnits = block.length / wordSize; - MemoryBlock memoryBlock = new MemoryBlock(startAddress, block.length, lenghtInaddressableUnits, block); - fMemoryBlockList.add(memoryBlock); - countingRM.done(); - } - }); - } - } - - /** + * @param address the memory block address (on the target) + * @param wordSize the size, in bytes, of an addressable item + * @param wordCount the number of addressable units to read + * @param drm the asynchronous data request monitor + */ + public void getMemory(IMemoryDMContext memoryDMC, final IAddress address, final int wordSize, + final int wordCount, final DataRequestMonitor<MemoryByte[]> drm) { + // Determine the number of read requests to issue + List<MemoryBlock> missingBlocks = getListOfMissingBlocks(address, wordCount, wordSize); + int numberOfRequests = missingBlocks.size(); + + // A read request will be issued for each block needed + // so we need to keep track of the count + final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), drm) { + @Override + protected void handleSuccess() { + // We received everything so read the result from the memory cache + drm.setData(getMemoryBlockFromCache(address, wordCount, wordSize)); + drm.done(); + } + }; + countingRM.setDoneCount(numberOfRequests); + + // Issue the read requests + for (int i = 0; i < numberOfRequests; i++) { + MemoryBlock block = missingBlocks.get(i); + final IAddress startAddress = block.fAddress; + final int length = (int) block.fLengthInAddressableUnits; + readMemoryBlock(memoryDMC, startAddress, 0, wordSize, length, + new DataRequestMonitor<MemoryByte[]>(getSession().getExecutor(), drm) { + @Override + protected void handleSuccess() { + MemoryByte[] block = getData(); + int lenghtInaddressableUnits = block.length / wordSize; + MemoryBlock memoryBlock = new MemoryBlock(startAddress, block.length, + lenghtInaddressableUnits, block); + fMemoryBlockList.add(memoryBlock); + countingRM.done(); + } + }); + } + } + + /** * @param memoryDMC - * @param address the memory block address (on the target) - * @param offset the offset from the start address - * @param wordSize the size, in bytes, of an addressable item - * @param wordCount the number of addressable units to write - * @param buffer the source buffer - * @param rm the asynchronous request monitor - */ - public void setMemory(final IMemoryDMContext memoryDMC, final IAddress address, - final long offset, final int wordSize, final int wordCount, final byte[] buffer, - final RequestMonitor rm) - { - writeMemoryBlock( - memoryDMC, address, offset, wordSize, wordCount, buffer, - new RequestMonitor(getSession().getExecutor(), rm) { - @Override - protected void handleSuccess() { - // Clear the command cache (otherwise we can't guarantee - // that the subsequent memory read will be correct) - fCommandCache.reset(); - - // Re-read the modified memory block to asynchronously update of the memory cache - readMemoryBlock(memoryDMC, address, offset, wordSize, wordCount, - new DataRequestMonitor<MemoryByte[]>(getExecutor(), rm) { - @Override - protected void handleSuccess() { - updateMemoryCache(address.add(offset), wordCount, getData(), wordSize); + * @param address the memory block address (on the target) + * @param offset the offset from the start address + * @param wordSize the size, in bytes, of an addressable item + * @param wordCount the number of addressable units to write + * @param buffer the source buffer + * @param rm the asynchronous request monitor + */ + public void setMemory(final IMemoryDMContext memoryDMC, final IAddress address, final long offset, + final int wordSize, final int wordCount, final byte[] buffer, final RequestMonitor rm) { + writeMemoryBlock(memoryDMC, address, offset, wordSize, wordCount, buffer, + new RequestMonitor(getSession().getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Clear the command cache (otherwise we can't guarantee + // that the subsequent memory read will be correct) + fCommandCache.reset(); + + // Re-read the modified memory block to asynchronously update of the memory cache + readMemoryBlock(memoryDMC, address, offset, wordSize, wordCount, + new DataRequestMonitor<MemoryByte[]>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + updateMemoryCache(address.add(offset), wordCount, getData(), wordSize); + // Send the MemoryChangedEvent + IAddress[] addresses = new IAddress[wordCount]; + for (int i = 0; i < wordCount; i++) { + addresses[i] = address.add(offset + i); + } + getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), + getProperties()); + rm.done(); + } + }); + } + }); + } + + /** + * @param memoryDMC + * @param address + * @param offset + * @param wordSize + * @param wordCount + * @param sendMemoryEvent Indicates if a IMemoryChangedEvent should be sent if the memory cache has changed. + * @param rm + */ + public void refreshMemory(final IMemoryDMContext memoryDMC, final IAddress address, final long offset, + final int wordSize, final int wordCount, final boolean sendMemoryEvent, final RequestMonitor rm) { + // Check if we already cache part of this memory area (which means it + // is used by a memory service client that will have to be updated) + List<MemoryBlock> list = getListOfMissingBlocks(address, wordCount, wordSize); + int sizeToRead = 0; + for (MemoryBlock block : list) { + sizeToRead += block.fLengthInAddressableUnits; + } + + // If none of the requested memory is in cache, just get out + if (sizeToRead == wordCount) { + rm.done(); + return; + } + + // Read the corresponding memory block + fCommandCache.reset(); + readMemoryBlock(memoryDMC, address, offset, wordSize, wordCount, + new DataRequestMonitor<MemoryByte[]>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + MemoryByte[] oldBlock = getMemoryBlockFromCache(address, wordCount, wordSize); + MemoryByte[] newBlock = getData(); + boolean blocksDiffer = false; + for (int i = 0; i < oldBlock.length; i++) { + if (oldBlock[i].getValue() != newBlock[i].getValue()) { + blocksDiffer = true; + break; + } + } + if (blocksDiffer) { + updateMemoryCache(address.add(offset), wordCount, newBlock, wordSize); + if (sendMemoryEvent) { // Send the MemoryChangedEvent - IAddress[] addresses = new IAddress[wordCount]; + final IAddress[] addresses = new IAddress[wordCount]; for (int i = 0; i < wordCount; i++) { addresses[i] = address.add(offset + i); } - getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties()); - rm.done(); - } - }); - } - }); - } - - /** - * @param memoryDMC - * @param address - * @param offset - * @param wordSize - * @param wordCount - * @param sendMemoryEvent Indicates if a IMemoryChangedEvent should be sent if the memory cache has changed. - * @param rm - */ - public void refreshMemory(final IMemoryDMContext memoryDMC, final IAddress address, - final long offset, final int wordSize, final int wordCount, final boolean sendMemoryEvent, - final RequestMonitor rm) - { - // Check if we already cache part of this memory area (which means it - // is used by a memory service client that will have to be updated) - List<MemoryBlock> list = getListOfMissingBlocks(address, wordCount, wordSize); - int sizeToRead = 0; - for (MemoryBlock block : list) { - sizeToRead += block.fLengthInAddressableUnits; - } - - // If none of the requested memory is in cache, just get out - if (sizeToRead == wordCount) { - rm.done(); - return; - } - - // Read the corresponding memory block - fCommandCache.reset(); - readMemoryBlock(memoryDMC, address, offset, wordSize, wordCount, - new DataRequestMonitor<MemoryByte[]>(getExecutor(), rm) { - @Override - protected void handleSuccess() { - MemoryByte[] oldBlock = getMemoryBlockFromCache(address, wordCount, wordSize); - MemoryByte[] newBlock = getData(); - boolean blocksDiffer = false; - for (int i = 0; i < oldBlock.length; i++) { - if (oldBlock[i].getValue() != newBlock[i].getValue()) { - blocksDiffer = true; - break; - } - } - if (blocksDiffer) { - updateMemoryCache(address.add(offset), wordCount, newBlock, wordSize); - if (sendMemoryEvent) { - // Send the MemoryChangedEvent - final IAddress[] addresses = new IAddress[wordCount]; - for (int i = 0; i < wordCount; i++) { - addresses[i] = address.add(offset + i); - } - getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties()); - } - } - rm.done(); - } - }); - } + getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), + getProperties()); + } + } + rm.done(); + } + }); + } } - /** - * {@inheritDoc} - * @since 1.1 - */ + /** + * {@inheritDoc} + * @since 1.1 + */ @Override - public void flushCache(IDMContext context) { - fCommandCache.reset(context); - - IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, IMemoryDMContext.class); - - if (memoryDMC != null) { - memoryCacheReset(memoryDMC); - } - } + public void flushCache(IDMContext context) { + fCommandCache.reset(context); + + IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, IMemoryDMContext.class); + + if (memoryDMC != null) { + memoryCacheReset(memoryDMC); + } + } /** * Reset the cache for the given memory context or any of its associated |