/*******************************************************************************
* Copyright (c) 2010, 2015 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
* Alvaro Sanchez-Leon (Ericsson AB) - [Memory] Support 16 bit addressable size (Bug 426730)
* Anders Dahlberg (Ericsson) - Need additional API to extend support for memory spaces (Bug 431627)
* Alvaro Sanchez-Leon (Ericsson AB) - Need additional API to extend support for memory spaces (Bug 431627)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.memory;
import java.math.BigInteger;
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
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.IMemoryDMContext;
import org.eclipse.cdt.dsf.debug.service.IMemorySpaces.IMemorySpaceDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.IGDBMemory;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
/**
* 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
*/
public 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.isEmpty()) ? memorySpaceID : null;
assert memorySpaceID == null || !memorySpaceID.isEmpty(); // callers shouldn't be passing in an empty string
//TODO: remove the memorySpaceID parameter from this method
//after making sure it's not used in earlier implementations
//in the mean time check for consistency
if(memorySpaceID != null) {
assert(context instanceof IMemorySpaceDMContext);
assert memorySpaceID.equals(((IMemorySpaceDMContext) context).getMemorySpaceId());
} else {
if (context instanceof IMemorySpaceDMContext) {
assert ((IMemorySpaceDMContext) context).getMemorySpaceId() == null;
}
}
}
/**
* 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});
// A memorySpaceDMContext should not be created if the memorySpaceId is not valid.
// However we need the id to calculate the hash, therefore we can not leave it as null
assert(memorySpaceId != null);
fMemorySpaceId = memorySpaceId == null ? "": memorySpaceId; //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IMemorySpaces.IMemorySpaceDMContext#getMemorySpaceId()
*/
@Override
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$
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemorySpaceAwareMemoryBlock#getMemorySpaceID()
*/
@Override
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.isEmpty();
GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval();
return retrieval.encodeAddress(super.getExpression(), fMemorySpaceID);
}
return super.getExpression();
}
@Override
public int getAddressSize() throws DebugException {
GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval();
IGDBMemory memoryService = (IGDBMemory)retrieval.getServiceTracker().getService();
if (memoryService != null) {
return memoryService.getAddressSize(getContext());
}
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null));
}
@Override
@DsfServiceEventHandler
public void eventDispatched(ISuspendedDMEvent e) {
super.eventDispatched(e);
if (e.getReason() == StateChangeReason.BREAKPOINT ||
e.getReason() == StateChangeReason.EVENT_BREAKPOINT ||
e.getReason() == StateChangeReason.WATCHPOINT) {
// If the session is suspended because of a breakpoint we need to
// fire DebugEvent.SUSPEND to force update for the "On Breakpoint" update mode.
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=406999.
DebugEvent debugEvent = new DebugEvent(this, DebugEvent.SUSPEND, DebugEvent.BREAKPOINT);
DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { debugEvent });
}
}
}