/******************************************************************************* * 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<MemoryByte[]> query = new Query<MemoryByte[]>() { @Override protected void execute(final DataRequestMonitor<MemoryByte[]> 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<MemoryByte[]>(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<MemoryByte[]> query = new Query<MemoryByte[]>() { @Override protected void execute(final DataRequestMonitor<MemoryByte[]> 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(); } }