blob: 82c0914934ecab0260a9dc1cb716da7f9f806fbf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Mentor Graphics 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:
* Mentor Graphics - Initial API and implementation
* John Dallaway - Add methods to get the endianness and address size (Bug 225609)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Sequence;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IMemory;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.MIMemory;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.CLIShowEndianInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataEvaluateExpressionInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.model.MemoryByte;
/**
* @since 4.2
*/
public class GDBMemory extends MIMemory implements IGDBMemory {
private IGDBControl fCommandControl;
/**
* Cache of the address sizes for each memory context.
*/
private Map<IMemoryDMContext, Integer> fAddressSizes = new HashMap<IMemoryDMContext, Integer>();
/**
* We assume the endianness is the same for all processes because GDB supports only one target.
*/
private Boolean fIsBigEndian;
public GDBMemory(DsfSession session) {
super(session);
}
@Override
public void initialize(final RequestMonitor requestMonitor) {
super.initialize(new ImmediateRequestMonitor(requestMonitor) {
@Override
protected void handleSuccess() {
doInitialize(requestMonitor);
}
});
}
private void doInitialize(final RequestMonitor requestMonitor) {
fCommandControl = getServicesTracker().getService(IGDBControl.class);
getSession().addServiceEventListener(this, null);
register(
new String[] {
IMemory.class.getName(),
MIMemory.class.getName(),
IGDBMemory.class.getName(),
GDBMemory.class.getName(),
},
new Hashtable<String, String>());
requestMonitor.done();
}
@Override
public void shutdown(RequestMonitor requestMonitor) {
unregister();
getSession().removeServiceEventListener(this);
fAddressSizes.clear();
super.shutdown(requestMonitor);
}
@Override
protected void readMemoryBlock(final IDMContext dmc, IAddress address,
long offset, int word_size, int count, final DataRequestMonitor<MemoryByte[]> drm) {
super.readMemoryBlock(
dmc,
address,
offset,
word_size,
count,
new DataRequestMonitor<MemoryByte[]>(ImmediateExecutor.getInstance(), drm) {
@Override
@ConfinedToDsfExecutor("fExecutor")
protected void handleSuccess() {
IMemoryDMContext memDmc = DMContexts.getAncestorOfType(dmc, IMemoryDMContext.class);
if (memDmc != null) {
boolean bigEndian = isBigEndian(memDmc);
for (MemoryByte b : getData()) {
b.setBigEndian(bigEndian);
b.setEndianessKnown(true);
}
}
drm.setData(getData());
drm.done();
}
});
}
@Override
public void initializeMemoryData(final IMemoryDMContext memContext, RequestMonitor rm) {
ImmediateExecutor.getInstance().execute(new Sequence(getExecutor(), rm) {
private Step[] fSteps = new Step[] {
new Step() {
@Override
public void execute(final RequestMonitor requestMonitor) {
Integer addrSize = fAddressSizes.get(memContext);
if (addrSize != null) {
requestMonitor.done();
return;
}
readAddressSize(
memContext,
new DataRequestMonitor<Integer>(ImmediateExecutor.getInstance(), requestMonitor) {
@Override
@ConfinedToDsfExecutor("fExecutor")
protected void handleSuccess() {
fAddressSizes.put(memContext, getData());
requestMonitor.done();
}
});
}
},
new Step() {
@Override
public void execute(final RequestMonitor requestMonitor) {
if ( fIsBigEndian != null) {
requestMonitor.done();
return;
}
readEndianness(
memContext,
new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), requestMonitor) {
@Override
@ConfinedToDsfExecutor("fExecutor")
protected void handleSuccess() {
fIsBigEndian = getData();
requestMonitor.done();
}
});
}
},
};
@Override
public Step[] getSteps() {
return fSteps;
}
});
}
@DsfServiceEventHandler
public void eventDispatched(IExitedDMEvent event) {
if (event.getDMContext() instanceof IContainerDMContext) {
IMemoryDMContext context = DMContexts.getAncestorOfType(event.getDMContext(), IMemoryDMContext.class);
if (context != null) {
fAddressSizes.remove(context);
}
}
}
@Override
public int getAddressSize(IMemoryDMContext context) {
Integer addressSize = fAddressSizes.get(context);
return (addressSize != null) ? addressSize.intValue() : 8;
}
@Override
public boolean isBigEndian(IMemoryDMContext context) {
assert fIsBigEndian != null;
if (fIsBigEndian == null) {
GdbPlugin.log(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Endianness was never initialized!")); //$NON-NLS-1$
return false;
}
return fIsBigEndian;
}
protected void readAddressSize(IMemoryDMContext memContext, final DataRequestMonitor<Integer> drm) {
IExpressions exprService = getServicesTracker().getService(IExpressions.class);
IExpressionDMContext exprContext = exprService.createExpression(memContext, "sizeof (void*)"); //$NON-NLS-1$
CommandFactory commandFactory = fCommandControl.getCommandFactory();
fCommandControl.queueCommand(
commandFactory.createMIDataEvaluateExpression(exprContext),
new DataRequestMonitor<MIDataEvaluateExpressionInfo>(ImmediateExecutor.getInstance(), drm) {
@Override
@ConfinedToDsfExecutor("fExecutor")
protected void handleSuccess() {
try {
drm.setData(Integer.decode(getData().getValue()));
}
catch(NumberFormatException e) {
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, String.format("Invalid address size: %s", getData().getValue()))); //$NON-NLS-1$
}
drm.done();
}
});
}
protected void readEndianness(IMemoryDMContext memContext, final DataRequestMonitor<Boolean> drm) {
CommandFactory commandFactory = fCommandControl.getCommandFactory();
fCommandControl.queueCommand(
commandFactory.createCLIShowEndian(memContext),
new DataRequestMonitor<CLIShowEndianInfo>(ImmediateExecutor.getInstance(), drm) {
@Override
@ConfinedToDsfExecutor("fExecutor")
protected void handleSuccess() {
drm.setData(Boolean.valueOf(getData().isBigEndian()));
drm.done();
}
});
}
}