diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF b/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF index 90536f4d3b8..2a034c791d7 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF @@ -21,10 +21,11 @@ Export-Package: org.eclipse.cdt.dsf.gdb, org.eclipse.cdt.dsf.gdb.actions, org.eclipse.cdt.dsf.gdb.breakpoints, org.eclipse.cdt.dsf.gdb.internal.commands, + org.eclipse.cdt.dsf.gdb.internal.memory;x-internal:=true, + org.eclipse.cdt.dsf.gdb.internal.tracepointactions, org.eclipse.cdt.dsf.gdb.launching, org.eclipse.cdt.dsf.gdb.service, org.eclipse.cdt.dsf.gdb.service.command, - org.eclipse.cdt.dsf.gdb.internal.tracepointactions, org.eclipse.cdt.dsf.mi.service, org.eclipse.cdt.dsf.mi.service.command, org.eclipse.cdt.dsf.mi.service.command.commands, diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/GdbMemoryBlock.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/GdbMemoryBlock.java new file mode 100644 index 00000000000..7f19800fbd9 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/GdbMemoryBlock.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2010, Texas Instruments, Freescale Semiconductor and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Texas Instruments, Freescale Semiconductor - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.memory; + +import java.math.BigInteger; +import java.util.concurrent.ExecutionException; + +import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlock; +import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval; +import org.eclipse.cdt.dsf.debug.service.IMemory; +import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.cdt.dsf.debug.service.IMemorySpaces; +import org.eclipse.cdt.dsf.debug.service.IMemorySpaces.IMemorySpaceDMContext; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.MemoryByte; + +/** + * A specialization of the DSF memory block implementation supporting memory + * spaces. The memory space support is provisional, thus this class is internal. + * + * @author Alain Lee and John Cortell + */ +public class GdbMemoryBlock extends DsfMemoryBlock implements IMemorySpaceAwareMemoryBlock { + + private final String fMemorySpaceID; + + /** + * Constructor + */ + GdbMemoryBlock(DsfMemoryBlockRetrieval retrieval, IMemoryDMContext context, + String modelId, String expression, BigInteger address, + int word_size, long length, String memorySpaceID) { + super(retrieval, context, modelId, expression, address, word_size, length); + fMemorySpaceID = (memorySpaceID != null && memorySpaceID.length() > 0) ? memorySpaceID : null; + assert memorySpaceID == null || memorySpaceID.length() > 0; // callers shouldn't be passing in an empty string + } + + /** + * A memory space qualified context for the IMemory methods. Used if + * required, otherwise the more basic IMemoryDMContext is used + */ + public static class MemorySpaceDMContext extends AbstractDMContext implements IMemorySpaceDMContext { + + private final String fMemorySpaceId; + + public MemorySpaceDMContext(String sessionId, String memorySpaceId, IDMContext parent) { + super(sessionId, new IDMContext[] {parent}); + fMemorySpaceId = memorySpaceId; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.service.IMemorySpaces.IMemorySpaceDMContext#getMemorySpaceId() + */ + public String getMemorySpaceId() { + return fMemorySpaceId; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#equals(java.lang.Object) + */ + @Override + public boolean equals(Object other) { + if (other instanceof MemorySpaceDMContext) { + MemorySpaceDMContext dmc = (MemorySpaceDMContext) other; + return (super.baseEquals(other)) && (dmc.fMemorySpaceId.equals(fMemorySpaceId)); + } else { + return false; + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#hashCode() + */ + @Override + public int hashCode() { + return super.baseHashCode() + fMemorySpaceId.hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return baseToString() + ".memoryspace[" + fMemorySpaceId + ']'; //$NON-NLS-1$ + } + } + + /* + * 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 bigAddress + * @param length + * @return MemoryByte[] + * @throws DebugException + */ + @Override + protected MemoryByte[] fetchMemoryBlock(BigInteger bigAddress, final long length) throws DebugException { + + // For the IAddress interface + final Addr64 address = new Addr64(bigAddress); + + // Use a Query to synchronize the downstream calls + Query query = new Query() { + @Override + protected void execute(final DataRequestMonitor drm) { + GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval(); + int addressableSize = 1; + try { + addressableSize = getAddressableSize(); + } catch (DebugException e) {} + + // If this block was created with a memory space qualification, + // we need to create an enhanced context + IMemoryDMContext context = null; + if (fMemorySpaceID != null) { + IMemorySpaces memoryService = (IMemorySpaces) retrieval.getMemorySpaceServiceTracker().getService(); + if (memoryService != null) { + context = new MemorySpaceDMContext(memoryService.getSession().getId(), fMemorySpaceID, getContext()); + } + else { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null)); + drm.done(); + return; + } + } + else { + context = getContext(); + } + + IMemory memoryService = (IMemory) retrieval.getServiceTracker().getService(); + if (memoryService != null) { + // Go for it + memoryService.getMemory( + context, address, 0, addressableSize, (int) length, + //getContext(), address, 0, addressableSize, (int) length, + new DataRequestMonitor(retrieval.getExecutor(), drm) { + @Override + protected void handleSuccess() { + drm.setData(getData()); + drm.done(); + } + }); + } + else { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null)); + drm.done(); + return; + } + } + }; + GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval(); + retrieval.getExecutor().execute(query); + + try { + return query.get(); + } catch (InterruptedException e) { + throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryReadFailed, e)); + } catch (ExecutionException e) { + throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryReadFailed, e)); + } + } + + /* Writes an array of bytes to memory. + * + * @param offset + * @param bytes + * @throws DebugException + */ + @Override + protected void writeMemoryBlock(final long offset, final byte[] bytes) throws DebugException { + + // For the IAddress interface + final Addr64 address = new Addr64(getBigBaseAddress()); + + // Use a Query to synchronize the downstream calls + Query query = new Query() { + @Override + protected void execute(final DataRequestMonitor drm) { + GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval(); + int addressableSize = 1; + // If this block was created with a memory space qualification, + // we need to create an enhanced context + IMemoryDMContext context = null; + if (fMemorySpaceID != null) { + IMemorySpaces memoryService = (IMemorySpaces) retrieval.getMemorySpaceServiceTracker().getService(); + if (memoryService != null) { + context = new MemorySpaceDMContext(memoryService.getSession().getId(), fMemorySpaceID, getContext()); + } + else { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null)); + drm.done(); + return; + } + } + else { + context = getContext(); + } + IMemory memoryService = (IMemory) retrieval.getServiceTracker().getService(); + if (memoryService != null) { + // Go for it + memoryService.setMemory( + context, address, offset, addressableSize, bytes.length, bytes, + new RequestMonitor(retrieval.getExecutor(), drm)); + } + else { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null)); + drm.done(); + return; + } + } + }; + GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval(); + retrieval.getExecutor().execute(query); + + try { + query.get(); + } catch (InterruptedException e) { + throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryWriteFailed, e)); + } catch (ExecutionException e) { + throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryWriteFailed, e)); + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemorySpaceAwareMemoryBlock#getMemorySpaceID() + */ + public String getMemorySpaceID() { + return fMemorySpaceID; + } + + /** + * Override this method to qualify the expression with the memory space, if + * applicable. + * + * @see org.eclipse.cdt.dsf.debug.model.DsfMemoryBlock#getExpression() + */ + @Override + public String getExpression() { + if (fMemorySpaceID != null) { + assert fMemorySpaceID.length() > 0; + GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval(); + return retrieval.encodeAddress(super.getExpression(), fMemorySpaceID); + } + return super.getExpression(); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/GdbMemoryBlockRetrieval.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/GdbMemoryBlockRetrieval.java new file mode 100644 index 00000000000..bbcd45a6d1c --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/GdbMemoryBlockRetrieval.java @@ -0,0 +1,365 @@ +/******************************************************************************* + * Copyright (c) 2010, Texas Instruments, Freescale Semiconductor and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Texas Instruments, Freescale Semiconductor - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.memory; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock; +import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlock; +import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval; +import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.cdt.dsf.debug.service.IMemorySpaces; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.service.DsfServices; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IMemoryBlockExtension; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.util.tracker.ServiceTracker; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A specialization of the DSF memory block retrieval implementation supporting + * memory spaces. The memory space support is provisional, thus this class is + * internal. + * + * @author Alain Lee and John Cortell + */ +public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements + IMemorySpaceAwareMemoryBlockRetrieval { + + private final ServiceTracker fMemorySpaceServiceTracker; + + // No need to use the constants in our base class. Serializing and + // recreating the blocks is done entirely by us + private static final String MEMORY_BLOCK_EXPRESSION_LIST = "memoryBlockExpressionList"; //$NON-NLS-1$ + private static final String ATTR_EXPRESSION_LIST_CONTEXT = "context"; //$NON-NLS-1$ + private static final String MEMORY_BLOCK_EXPRESSION = "gdbmemoryBlockExpression"; //$NON-NLS-1$ + private static final String ATTR_MEMORY_BLOCK_EXPR_LABEL = "label"; //$NON-NLS-1$ + private static final String ATTR_MEMORY_BLOCK_EXPR_ADDRESS = "address"; //$NON-NLS-1$ + private static final String ATTR_MEMORY_BLOCK_MEMORY_SPACE_ID = "memorySpaceID"; //$NON-NLS-1$ + + /** see comment in base class */ + private static final String CONTEXT_RESERVED = "reserved-for-future-use"; //$NON-NLS-1$ + + /** + * Constructor + */ + public GdbMemoryBlockRetrieval(String modelId, ILaunchConfiguration config, + DsfSession session) throws DebugException { + super(modelId, config, session); + + + BundleContext bundle = GdbPlugin.getBundleContext(); + + // Create a tracker for the MemoryPageService + String memoryPageServiceFilter = DsfServices.createServiceFilter(IMemorySpaces.class, session.getId()); + + try { + fMemorySpaceServiceTracker = new ServiceTracker( + bundle, bundle.createFilter(memoryPageServiceFilter), null); + } catch (InvalidSyntaxException e) { + throw new DebugException(new Status(IStatus.ERROR, + GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, + "Error creating service filter.", e)); //$NON-NLS-1$ + } + fMemorySpaceServiceTracker.open(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval#getExtendedMemoryBlock(java.lang.String, java.lang.Object) + */ + @Override + public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException { + // Technically, we don't need to override this method. Letting our base + // class create a DsfMemoryBlock would work just fine. But, for the + // sake of consistency, lets have this retrieval class always return a + // GdbMemoryBlock. + return getMemoryBlock(expression, context, null); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval#getExtendedMemoryBlock(java.lang.String, java.lang.Object, java.lang.String) + */ + public IMemorySpaceAwareMemoryBlock getMemoryBlock(String expression, Object context, String memorySpaceID) throws DebugException { + // Drill for the actual DMC + IMemoryDMContext memoryDmc = null; + IDMContext dmc = null; + if (context instanceof IAdaptable) { + dmc = (IDMContext)((IAdaptable)context).getAdapter(IDMContext.class); + if (dmc != null) { + memoryDmc = DMContexts.getAncestorOfType(dmc, IMemoryDMContext.class); + } + } + + if (memoryDmc == null) { + return null; + } + + // The block start address (supports 64-bit processors) + BigInteger blockAddress; + + /* + * 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; + + // Check for "hexadecimality" + if (expression.startsWith("0x") || expression.startsWith("0X")) { //$NON-NLS-1$//$NON-NLS-2$ + base = 16; + offset = 2; + } + // Check for "binarity" + else if (expression.startsWith("0b")) { //$NON-NLS-1$ + base = 2; + offset = 2; + } + // Check for "octality" + else if (expression.startsWith("0")) { //$NON-NLS-1$ + base = 8; + offset = 1; + } + // 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); + + } 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' + + // Resolve the expression + blockAddress = resolveMemoryAddress(dmc, 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 GdbMemoryBlock(this, memoryDmc, getModelId(), expression, blockAddress, getAddressableSize(), 0, memorySpaceID); + } + + /* + * implementation of + * @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemorySpaceManagement#getMemorySpaces(Object context) + */ + public void getMemorySpaces(final Object context, final GetMemorySpacesRequest request) { + Query query = new Query() { + @Override + protected void execute(final DataRequestMonitor drm) { + IDMContext dmc = null; + if (context instanceof IAdaptable) { + dmc = (IDMContext)((IAdaptable)context).getAdapter(IDMContext.class); + if (dmc != null) { + IMemorySpaces memoryPageService = (IMemorySpaces)fMemorySpaceServiceTracker.getService(); + if (memoryPageService != null) { + memoryPageService.getMemorySpaces( + dmc, + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleCompleted() { + // Store the result + if (isSuccess()) { + request.setMemorySpaces(getData()); + } + else { + request.setStatus(getStatus()); + } + request.done(); + drm.done(); // don't bother with status; we don't check it below + } + }); + } + else { + request.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryServiceNotAvailable, null)); + request.done(); + drm.done(); + } + } + } + } + }; + getExecutor().execute(query); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval#encodeAddress(java.lang.String, java.lang.String) + */ + public String encodeAddress(String expression, String memorySpaceID) { + String result = null; + IMemorySpaces service = (IMemorySpaces)fMemorySpaceServiceTracker.getService(); + if (service != null) { + // the service can tell us to use our default encoding by returning null + result = service.encodeAddress(expression, memorySpaceID); + } + if (result == null) { + // default encoding + result = memorySpaceID + ':' + expression; + } + return result; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval#decodeAddress(java.lang.String) + */ + public DecodeResult decodeAddress(String str) throws CoreException { + IMemorySpaces memoryPageService = (IMemorySpaces)fMemorySpaceServiceTracker.getService(); + if (memoryPageService != null) { + final IMemorySpaces.DecodeResult result = memoryPageService.decodeAddress(str); + if (result != null) { // service can return null to tell use to use default decoding + return new DecodeResult() { + public String getMemorySpaceId() { return result.getMemorySpaceId(); } + public String getExpression() { return result.getExpression(); } + }; + } + } + + // default decoding + int index = str.indexOf(':'); + if (index == -1) { + throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, Messages.Err_InvalidEncodedAddress + ": " + str , null)); //$NON-NLS-1$ + } + + final String memorySpaceID = str.substring(0, index); + final String expression = (index < str.length()-1) ? str.substring(index+1) : ""; //$NON-NLS-1$ + return new DecodeResult() { + public String getMemorySpaceId() { return memorySpaceID; } + public String getExpression() { return expression; } + }; + + } + + ServiceTracker getMemorySpaceServiceTracker() { + return fMemorySpaceServiceTracker; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval#getMemento() + */ + @Override + public String getMemento() throws CoreException { + IMemoryBlock[] blocks = DebugPlugin.getDefault().getMemoryBlockManager().getMemoryBlocks(this); + Document document = DebugPlugin.newDocument(); + Element expressionList = document.createElement(MEMORY_BLOCK_EXPRESSION_LIST); + expressionList.setAttribute(ATTR_EXPRESSION_LIST_CONTEXT, CONTEXT_RESERVED); + for (IMemoryBlock block : blocks) { + if (block instanceof IMemoryBlockExtension) { + IMemoryBlockExtension memoryBlock = (IMemoryBlockExtension) block; + Element expression = document.createElement(MEMORY_BLOCK_EXPRESSION); + expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_ADDRESS, memoryBlock.getBigBaseAddress().toString()); + if (block instanceof IMemorySpaceAwareMemoryBlock) { + String memorySpaceID = ((IMemorySpaceAwareMemoryBlock)memoryBlock).getMemorySpaceID(); + if (memorySpaceID != null) { + expression.setAttribute(ATTR_MEMORY_BLOCK_MEMORY_SPACE_ID, memorySpaceID); + + // What we return from GdbMemoryBlock#getExpression() + // is the encoded representation. We need to decode it + // to get the original expression used to create the block + DecodeResult result = ((IMemorySpaceAwareMemoryBlockRetrieval)memoryBlock.getMemoryBlockRetrieval()).decodeAddress(memoryBlock.getExpression()); + expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL, result.getExpression()); + } + else { + expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL, memoryBlock.getExpression()); + } + } + else { + assert false; // should never happen (see getExtendedMemoryBlock()), but we can handle it. + expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL, memoryBlock.getExpression()); + } + expressionList.appendChild(expression); + } + } + document.appendChild(expressionList); + return DebugPlugin.serializeDocument(document); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval#createBlocksFromConfiguration(org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext, java.lang.String) + */ + @Override + protected void createBlocksFromConfiguration(IMemoryDMContext memoryCtx, String memento) throws CoreException { + + // Parse the memento and validate its type + Element root = DebugPlugin.parseDocument(memento); + if (!root.getNodeName().equalsIgnoreCase(MEMORY_BLOCK_EXPRESSION_LIST)) { + IStatus status = new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugPlugin.INTERNAL_ERROR, + "Memory monitor initialization: invalid memento", null);//$NON-NLS-1$ + throw new CoreException(status); + } + + // Process the block list specific to this memory context + // FIXME: (Bug228573) We only process the first entry... + if (root.getAttribute(ATTR_EXPRESSION_LIST_CONTEXT).equals(CONTEXT_RESERVED)) { + List blocks = new ArrayList(); + NodeList expressionList = root.getChildNodes(); + int length = expressionList.getLength(); + for (int i = 0; i < length; ++i) { + Node node = expressionList.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element entry = (Element) node; + if (entry.getNodeName().equalsIgnoreCase(MEMORY_BLOCK_EXPRESSION)) { + String label = entry.getAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL); + String address = entry.getAttribute(ATTR_MEMORY_BLOCK_EXPR_ADDRESS); + + String memorySpaceID = null; + if (entry.hasAttribute(ATTR_MEMORY_BLOCK_MEMORY_SPACE_ID)) { + memorySpaceID = entry.getAttribute(ATTR_MEMORY_BLOCK_MEMORY_SPACE_ID); + if (memorySpaceID.length() == 0) { + memorySpaceID = null; + assert false : "should have either no memory space or a valid (non-empty) ID"; //$NON-NLS-1$ + } + } + + BigInteger blockAddress = new BigInteger(address); + DsfMemoryBlock block = new GdbMemoryBlock(this, memoryCtx, getModelId(), label, blockAddress, getAddressableSize(), 0, memorySpaceID); + blocks.add(block); + } + } + } + DebugPlugin.getDefault().getMemoryBlockManager().addMemoryBlocks( blocks.toArray(new IMemoryBlock[blocks.size()])); + } + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/Messages.java new file mode 100644 index 00000000000..83f2cea57b6 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/Messages.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Freescale Semiconductor - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.memory; + +import org.eclipse.osgi.util.NLS; + +/** + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class Messages extends NLS { + static { + NLS.initializeMessages("org.eclipse.cdt.dsf.gdb.internal.memory.messages", Messages.class); //$NON-NLS-1$ + } + + public static String Err_MemoryServiceNotAvailable; + public static String Err_MemoryReadFailed; + public static String Err_MemoryWriteFailed; + public static String Err_InvalidEncodedAddress; +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/messages.properties new file mode 100644 index 00000000000..9a8f8148b26 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/memory/messages.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2010 Freescale Semiconductor and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Freescale Semiconductor - initial API and implementation +############################################################################### + +Err_MemoryServiceNotAvailable=The required DSF memory service is not available. +Err_MemoryReadFailed=Error reading memory block +Err_MemoryWriteFailed=Error writing memory block +Err_InvalidEncodedAddress=Encoded address has unexpected format \ No newline at end of file diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java index 470aafa91f3..1a34fc9d660 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java @@ -32,6 +32,7 @@ import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.internal.memory.GdbMemoryBlockRetrieval; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.MIProcesses; @@ -117,7 +118,7 @@ public class GdbLaunch extends DsfLaunch ICommandControlService commandControl = fTracker.getService(ICommandControlService.class); IMIProcesses procService = fTracker.getService(IMIProcesses.class); if (commandControl != null && procService != null) { - fMemRetrieval = new DsfMemoryBlockRetrieval( + fMemRetrieval = new GdbMemoryBlockRetrieval( GdbLaunchDelegate.GDB_DEBUG_MODEL_ID, getLaunchConfiguration(), fSession); fSession.registerModelAdapter(IMemoryBlockRetrieval.class, fMemRetrieval); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBMemory_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBMemory_7_0.java index 90ddaddde70..d36cbfc6f7a 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBMemory_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBMemory_7_0.java @@ -18,6 +18,8 @@ import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IMemory; +import org.eclipse.cdt.dsf.debug.service.IMemorySpaces.IMemorySpaceDMContext; +import org.eclipse.cdt.dsf.gdb.internal.memory.GdbMemoryBlock.MemorySpaceDMContext; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.MIMemory; @@ -68,6 +70,12 @@ public class GDBMemory_7_0 extends MIMemory { // Return any thread... let's take the first one. if (execCtxs != null && execCtxs.length > 0) { threadOrMemoryDmc = execCtxs[0]; + + // Not so fast, Charlie. The context we were given may have + // a memory space qualifier. We need to preserve it. + if (dmc instanceof IMemorySpaceDMContext) { + threadOrMemoryDmc = new MemorySpaceDMContext(getSession().getId(), ((IMemorySpaceDMContext)dmc).getMemorySpaceId(), threadOrMemoryDmc); + } } } } @@ -90,6 +98,12 @@ public class GDBMemory_7_0 extends MIMemory { // Return any thread... let's take the first one. if (execCtxs != null && execCtxs.length > 0) { threadOrMemoryDmc = execCtxs[0]; + + // Not so fast, Charlie. The context we were given may have + // a memory space qualifier. We need to preserve it. + if (dmc instanceof IMemorySpaceDMContext) { + threadOrMemoryDmc = new MemorySpaceDMContext(getSession().getId(), ((IMemorySpaceDMContext)dmc).getMemorySpaceId(), threadOrMemoryDmc); + } } } } diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java index 3c0161c8399..9af1a96c5ee 100644 --- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java @@ -87,8 +87,9 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @param address - the actual memory block start address * @param word_size - the number of bytes per address * @param length - the requested block length (could be 0) + * @since 2.1 */ - DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, IMemoryDMContext context, String modelId, String expression, BigInteger address, int word_size, long length) { + protected DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, IMemoryDMContext context, String modelId, String expression, BigInteger address, int word_size, long length) { fLaunch = retrieval.getLaunch(); fDebugTarget = retrieval.getDebugTarget(); fRetrieval = retrieval; @@ -121,7 +122,7 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens /* (non-Javadoc) * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) */ - @SuppressWarnings("unchecked") + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Object getAdapter(Class adapter) { if (adapter.isAssignableFrom(DsfMemoryBlockRetrieval.class)) { @@ -557,7 +558,7 @@ 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. @@ -566,8 +567,9 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens * @param length * @return MemoryByte[] * @throws DebugException + * @since 2.1 */ - private MemoryByte[] fetchMemoryBlock(BigInteger bigAddress, final long length) throws DebugException { + protected MemoryByte[] fetchMemoryBlock(BigInteger bigAddress, final long length) throws DebugException { // For the IAddress interface final Addr64 address = new Addr64(bigAddress); @@ -605,13 +607,15 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens } } - /* Writes an array of bytes to memory. + /** + * Writes an array of bytes to memory. * * @param offset * @param bytes * @throws DebugException - */ - private void writeMemoryBlock(final long offset, final byte[] bytes) throws DebugException { + * @since 2.1 + */ + protected void writeMemoryBlock(final long offset, final byte[] bytes) throws DebugException { // For the IAddress interface final Addr64 address = new Addr64(fBaseAddress); @@ -707,4 +711,13 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens public String getUpdatePolicyDescription(String id) { return id; } + + /** + * Get the context specified at construction. + * + * @since 2.1 + */ + protected IMemoryDMContext getContext() { + return fContext; + } } diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java index c79f971f409..dfbfbc77c9f 100644 --- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java @@ -230,7 +230,14 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl } } - private void createBlocksFromConfiguration(IMemoryDMContext memoryCtx, String memento) throws CoreException { + /** + * Create memory blocks based on the given memento (obtained from the launch + * configuration) and add them to the platform's IMemoryBlockManager. The + * memento was previously created by {@link #getMemento()} + * + * @since 2.1 + */ + protected void createBlocksFromConfiguration(IMemoryDMContext memoryCtx, String memento) throws CoreException { // Parse the memento and validate its type Element root = DebugPlugin.parseDocument(memento); @@ -280,6 +287,15 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl } } + /** + * Create a memento to represent all active blocks created by this retrieval + * object (blocks currently registered with the platform's + * IMemoryBlockManager). We will be expected to recreate the blocks in + * {@link #createBlocksFromConfiguration(IMemoryDMContext, String)}. + * + * @return a string memento + * @throws CoreException + */ public String getMemento() throws CoreException { IMemoryBlock[] blocks = DebugPlugin.getDefault().getMemoryBlockManager().getMemoryBlocks(this); Document document = DebugPlugin.newDocument(); @@ -355,11 +371,8 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl return true; } - /* - * (non-Javadoc) - * - * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, - * long) + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long) */ public IMemoryBlock getMemoryBlock(final long startAddress, final long length) throws DebugException { throw new DebugException(new Status( @@ -457,7 +470,10 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl // Helper functions /////////////////////////////////////////////////////////////////////////// - private BigInteger resolveMemoryAddress(final IDMContext dmc, final String expression) throws DebugException { + /** + * @since 2.1 + */ + protected BigInteger resolveMemoryAddress(final IDMContext dmc, final String expression) throws DebugException { // Use a Query to "synchronize" the downstream calls Query query = new Query() { @@ -502,5 +518,15 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl "Error evaluating memory address (ExecutionException).", e)); //$NON-NLS-1$ } } + + + /** + * Return the model ID specified at construction + * + * @since 2.1 + */ + protected String getModelId() { + return fModelId; + } } diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemorySpaces.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemorySpaces.java new file mode 100644 index 00000000000..e5396f814ce --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemorySpaces.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2010, Texas Instruments, Freescale Semiconductor and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Texas Instruments, Freescale Semiconductor - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.service; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.cdt.dsf.service.IDsfService; +import org.eclipse.core.runtime.CoreException; + +/** + * A memory service that is memory space aware. + * + *

+ * Memory contexts are not meant to be represented in tree or table views, so it + * doesn't need to implement IDMService interface. + * + * @author Alain Lee and John Cortell + * @since 2.1 + */ +public interface IMemorySpaces extends IDsfService{ + + public interface IMemorySpaceDMContext extends IMemoryDMContext { + public String getMemorySpaceId(); + } + + /** + * Optionally provides the string encoding of a memory space qualified + * address. CDT provides a default encoding of + * [memory-space-id]:[expression]. If this is adequate, the client can + * return null from this method. This method is called when having to + * represent a memory-space qualified address as a single string. + * + * @param expression + * the expression representing a location within a memory space. + * This can be a simple numeric expression like "0x10000" or + * something more complex "$EAX+(gCustomerCount*100)". + * @param memorySpaceID + * a string which represents the memory space + * @return the encoded string representation of the address, or null to + * indicate no custom encoding is required + */ + String encodeAddress(String expression, String memorySpaceID); + + /** + * The inverse of {@link #encodeAddress(String, String)}. Client should + * provide decoding if it provides encoding. Conversely, it should not + * provide decoding if it doesn't provide encoding. + * + * @param str + * the encoded string + * @return the result of decoding the string into its components, or null to + * indicate no custom decoding is required + * @throws CoreException + * if decoding and string is not in the expected format + */ + DecodeResult decodeAddress(String str) throws CoreException; + + interface DecodeResult { + String getMemorySpaceId(); + String getExpression(); + } + + /** + * Provides the memory spaces available in the given context. + * + * @param ctx a DM context + * @param rm the asynchronous data request monitor + */ + void getMemorySpaces(IDMContext context, final DataRequestMonitor rm); +}