/*******************************************************************************
* Copyright (c) 2006, 2015 Wind River Systems 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:
* Wind River Systems - initial API and implementation
* Ericsson - Modified for additional features in DSF Reference Implementation
* Roland Grunberg (RedHat) - Refresh all registers once one is changed (Bug 400840)
* Alvaro Sanchez-Leon (Ericsson) - Make Registers View specific to a frame (Bug 323552)
* Alvaro Sanchez-Leon (Ericsson) - Register view does not refresh register names per process (Bug 418176)
* Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IRegisters;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
import org.eclipse.cdt.dsf.debug.service.IStack;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterNamesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterValuesInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIRegisterValue;
import org.eclipse.cdt.dsf.service.AbstractDsfService;
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.osgi.framework.BundleContext;
/**
*
* <p>
* Implementation note:
* This class implements event handlers for the events that are generated by
* this service itself. When the event is dispatched, these handlers will
* be called first, before any of the clients. These handlers update the
* service's internal state information to make them consistent with the
* events being issued. Doing this in the handlers as opposed to when
* the events are generated, guarantees that the state of the service will
* always be consistent with the events.
*/
public class MIRegisters extends AbstractDsfService implements IRegisters, ICachingService {
/**
* @since 4.6
*/
protected static final String BLANK_STRING = ""; //$NON-NLS-1$
/**
* @since 4.6
*/
protected static final String ROOT_GROUP_NAME = Messages.MIRegisters_General_Registers;
/**
* @since 4.6
*/
protected static final String ROOT_GROUP_DESCRIPTION = Messages.MIRegisters_General_Registers_description;
/*
* Support class used to construct Register Group DMCs.
*/
public static class MIRegisterGroupDMC extends AbstractDMContext implements IRegisterGroupDMContext {
private int fGroupNo;
private String fGroupName;
public MIRegisterGroupDMC(MIRegisters service, IContainerDMContext contDmc, int groupNo, String groupName) {
super(service.getSession().getId(), new IDMContext[] { contDmc });
fGroupNo = groupNo;
fGroupName = groupName;
}
public int getGroupNo() { return fGroupNo; }
public String getName() { return fGroupName; }
/**
* @since 4.6
*/
public void setName(String groupName) {
fGroupName = groupName;
}
@Override
public boolean equals(Object other) {
return ((super.baseEquals(other)) && (((MIRegisterGroupDMC) other).fGroupNo == fGroupNo) &&
(((MIRegisterGroupDMC) other).fGroupName.equals(fGroupName)));
}
@Override
public int hashCode() { return super.baseHashCode() ^ fGroupNo; }
@Override
public String toString() { return baseToString() + ".group[" + fGroupNo + "," + fGroupName + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/*
* Support class used to construct Register DMCs.
*/
public static class MIRegisterDMC extends AbstractDMContext implements IRegisterDMContext {
private int fRegNo;
private String fRegName;
/**
* An MIRegiserDMC created with no frame context will not be able to resolve the associated register value.
* However these instances are useful to provide the register name i.e. needed from the selection of a process,
* or a running thread where it is not possible to associate registers to frames and therefore values.
*/
public MIRegisterDMC(MIRegisters service, MIRegisterGroupDMC group, int regNo, String regName) {
super(service.getSession().getId(),
new IDMContext[] { group });
fRegNo = regNo;
fRegName = regName;
}
@Deprecated
public MIRegisterDMC(MIRegisters service, MIRegisterGroupDMC group, IMIExecutionDMContext execDmc, int regNo, String regName) {
super(service.getSession().getId(),
new IDMContext[] { execDmc, group });
fRegNo = regNo;
fRegName = regName;
}
/**
* This Register context is associated to two parent contexts. A stack frame context (IFrameDMContext), and a
* register group context (MIRegisterGroupDMC). When the scenario requires to build a register contexts from the
* selection of a thread, then the top frame shall be resolved and be provided in this constructor.
*
* The frame context is necessary to resolve the register's data e.g. value
*
* @since 4.3
*/
public MIRegisterDMC(MIRegisters service, MIRegisterGroupDMC group, IFrameDMContext frameDmc, int regNo,
String regName) {
super(service.getSession().getId(), new IDMContext[] { frameDmc, group });
fRegNo = regNo;
fRegName = regName;
}
public int getRegNo() { return fRegNo; }
public String getName() { return fRegName; }
@Override
public boolean equals(Object other) {
return ((super.baseEquals(other)) && (((MIRegisterDMC) other).fRegNo == fRegNo) &&
(((MIRegisterDMC) other).fRegName.equals(fRegName)));
}
@Override
public int hashCode() { return super.baseHashCode() ^ fRegNo; }
@Override
public String toString() { return baseToString() + ".register[" + fRegNo + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
}
/*
* Event class to notify register value is changed
*/
public static class RegisterChangedDMEvent implements IRegisters.IRegisterChangedDMEvent {
private final IRegisterDMContext fRegisterDmc;
/**
* @since 4.6
*/
public RegisterChangedDMEvent(IRegisterDMContext registerDMC) {
fRegisterDmc = registerDMC;
}
@Override
public IRegisterDMContext getDMContext() {
return fRegisterDmc;
}
}
/**
* Indicates a change in the list of Register groups e.g. after addition and removal
* @since 4.6
*/
public static class GroupsChangedDMEvent implements IRegisters.IGroupsChangedDMEvent {
private final IContainerDMContext fGroupContainerDmc;
public GroupsChangedDMEvent(IContainerDMContext containerDMC) {
fGroupContainerDmc = containerDMC;
}
@Override
public IContainerDMContext getDMContext() {
return fGroupContainerDmc;
}
}
/*
* Internal control variables.
*/
private CommandFactory fCommandFactory;
//One Group per container process
private final Map<IContainerDMContext, MIRegisterGroupDMC> fContainerToGroupMap = new HashMap<IContainerDMContext, MIRegisterGroupDMC>();
private CommandCache fRegisterNameCache; // Cache for holding the Register Names in the single Group
private CommandCache fRegisterValueCache; // Cache for holding the Register Values
public MIRegisters(DsfSession session)
{
super(session);
}
@Override
protected BundleContext getBundleContext()
{
return GdbPlugin.getBundleContext();
}
@Override
public void initialize(final RequestMonitor requestMonitor) {
super.initialize(
new ImmediateRequestMonitor(requestMonitor) {
@Override
protected void handleSuccess() {
doInitialize(requestMonitor);
}});
}
private void doInitialize(RequestMonitor requestMonitor) {
/*
* Create the lower level register cache.
*/
ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class);
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(commandControl, getExecutor(), 2);
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
// three scheduling of the executor, while command results after only one. This
// can cause problems because command results might be processed before an event
// that actually arrived before the command result.
// To solve this, we use a bufferedCommandControl that will delay the command
// result by two scheduling of the executor.
// See bug 280461
fRegisterValueCache = new CommandCache(getSession(), bufferedCommandControl);
fRegisterValueCache.setContextAvailable(commandControl.getContext(), true);
// This cache is not affected by events so does not need the bufferedCommandControl
fRegisterNameCache = new CommandCache(getSession(), commandControl);
fRegisterNameCache.setContextAvailable(commandControl.getContext(), true);
/*
* Sign up so we see events. We use these events to decide how to manage
* any local caches we are providing as well as the lower level register
* cache we create to get/set registers on the target.
*/
getSession().addServiceEventListener(this, null);
/*
* Make ourselves known so clients can use us.
*/
register(new String[]{IRegisters.class.getName(), MIRegisters.class.getName()}, new Hashtable<String,String>());
requestMonitor.done();
}
@Override
public void shutdown(RequestMonitor requestMonitor)
{
unregister();
getSession().removeServiceEventListener(this);
super.shutdown(requestMonitor);
}
public boolean isValid() { return true; }
@Override
public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor<FormattedValueDMData> rm) {
if (dmc.getParents().length == 1 && dmc.getParents()[0] instanceof MIRegisterDMC) {
getRegisterDataValue( (MIRegisterDMC) dmc.getParents()[0], dmc.getFormatID(), rm);
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
rm.done();
}
}
@Override
public void getRegisterGroupData(IRegisterGroupDMContext regGroupDmc, DataRequestMonitor<IRegisterGroupDMData> rm) {
/**
* For the GDB GDBMI implementation there is only on group. The GPR and FPU registers are grouped into
* one set. We are going to hard wire this set as the value of ROOT_GROUP_NAME.
*/
class RegisterGroupData implements IRegisterGroupDMData {
@Override
public String getName() { return ROOT_GROUP_NAME; }
@Override
public String getDescription() { return ROOT_GROUP_DESCRIPTION; }
}
rm.setData( new RegisterGroupData() ) ;
rm.done();
}
@Override
public void getBitFieldData(IBitFieldDMContext dmc, DataRequestMonitor<IBitFieldDMData> rm) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Bit fields not yet supported", null)); //$NON-NLS-1$
rm.done();
}
/**
* For the GDB GDBMI implementation there is only on group. We represent
* this group as a single list we maintain within this service. So we
* need to search this list to see if we have a current value.
*/
@Override
public void getRegisterData(IRegisterDMContext regDmc , final DataRequestMonitor<IRegisterDMData> rm) {
if (regDmc instanceof MIRegisterDMC) {
final MIRegisterDMC miRegDmc = (MIRegisterDMC)regDmc;
final IFrameDMContext frameDmc = DMContexts.getAncestorOfType(regDmc, IFrameDMContext.class);
// Create register data with name only e.g. not editable.
if(frameDmc == null){
rm.setData(new RegisterData(null, miRegDmc.getName(), BLANK_STRING, false));
rm.done();
return;
}
int[] regnos = {miRegDmc.getRegNo()};
fRegisterValueCache.execute(
fCommandFactory.createMIDataListRegisterValues(frameDmc, MIFormat.HEXADECIMAL, regnos),
new DataRequestMonitor<MIDataListRegisterValuesInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
// Retrieve the register value.
MIRegisterValue[] regValue = getData().getMIRegisterValues();
// If the list is empty just return empty handed.
// The only known case this happens is caused by a bug in GDB's Python
// scripts. See https://sourceware.org/bugzilla/show_bug.cgi?id=19637
// In this case, we know the register name anyway, we just guess that
// it is not floating point. The matching code in getRegisterDataValue()
// displays the error with link to a workaround
if (regValue.length == 0) {
rm.setData(new RegisterData(frameDmc, miRegDmc.getName(), BLANK_STRING, false));
rm.done();
return;
}
// the request was for only one register
assert regValue.length == 1;
// We can determine if the register is floating point because
// GDB returns this additional information as part of the value.
MIRegisterValue reg = regValue[0];
boolean isFloat = false;
if ( reg.getValue().contains("float")) { //$NON-NLS-1$
isFloat = true;
}
// Return the new register attributes.
rm.setData(new RegisterData(frameDmc, miRegDmc.getName(), BLANK_STRING, isFloat));
rm.done();
}
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown DMC type", null)); //$NON-NLS-1$
rm.done();
}
}
private void getRegisterDataValue( final MIRegisterDMC regDmc, final String formatId, final DataRequestMonitor<FormattedValueDMData> rm) {
IFrameDMContext frameDmc = DMContexts.getAncestorOfType(regDmc, IFrameDMContext.class);
if(frameDmc == null){
// Set value to blank if frame dmc is not present
rm.setData( new FormattedValueDMData( BLANK_STRING ) );
rm.done();
return;
}
// Select the format to be shown
int NumberFormat = MIFormat.HEXADECIMAL;
if ( HEX_FORMAT.equals ( formatId ) ) { NumberFormat = MIFormat.HEXADECIMAL; }
if ( OCTAL_FORMAT.equals ( formatId ) ) { NumberFormat = MIFormat.OCTAL; }
if ( NATURAL_FORMAT.equals( formatId ) ) { NumberFormat = MIFormat.NATURAL; }
if ( BINARY_FORMAT.equals ( formatId ) ) { NumberFormat = MIFormat.BINARY; }
if ( DECIMAL_FORMAT.equals( formatId ) ) { NumberFormat = MIFormat.DECIMAL; }
int[] regnos = {regDmc.getRegNo()};
fRegisterValueCache.execute(
fCommandFactory.createMIDataListRegisterValues(frameDmc, NumberFormat, regnos),
new DataRequestMonitor<MIDataListRegisterValuesInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
// Retrieve the register value.
MIRegisterValue[] regValue = getData().getMIRegisterValues();
// If the list is empty just return empty handed.
// The only known case this happens is caused by a bug in GDB's Python
// scripts. See https://sourceware.org/bugzilla/show_bug.cgi?id=19637
// In the display data, we show link to Eclipse Bugzilla entry which has
// a comment on how to fix this manually.
if (regValue.length == 0) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
IDsfStatusConstants.REQUEST_FAILED,
"Encountered a GDB Error See http://eclip.se/506382#c7 for workarounds", null)); //$NON-NLS-1$
rm.done();
return;
}
MIRegisterValue reg = regValue[0];
// Return the new register value.
rm.setData( new FormattedValueDMData( reg.getValue() ) );
rm.done();
}
});
}
/**
* @since 4.6
*/
protected static class RegisterData implements IRegisterDMData {
final private String fRegName;
final private String fRegDesc;
final private boolean fIsFloat;
final private IFrameDMContext fContext;
public RegisterData(IFrameDMContext context, String regName, String regDesc, boolean isFloat ) {
fRegName = regName;
fRegDesc = regDesc;
fIsFloat = isFloat;
fContext = context;
}
@Override
public boolean isReadable() { return true; }
@Override
public boolean isReadOnce() { return false; }
@Override
public boolean isWriteable() {
//The absence of the frame context is likely the result of a selection not specific to a stack frame
//e.g. the selection of a running thread, or the selection of a process.
//So, an instance with no stack frame is not writable
return (fContext != null);
}
@Override
public boolean isWriteOnce() { return false; }
@Override
public boolean hasSideEffects() { return false; }
@Override
public boolean isVolatile() { return true; }
@Override
public boolean isFloat() { return fIsFloat; }
@Override
public String getName() { return fRegName; }
@Override
public String getDescription() { return fRegDesc; }
}
// Wraps a list of registers in DMContexts.
private MIRegisterDMC[] makeRegisterDMCs(MIRegisterGroupDMC groupDmc, String[] regNames) {
return makeRegisterDMCs(groupDmc, null, regNames);
}
// Wraps a list of registers in DMContexts.
private MIRegisterDMC[] makeRegisterDMCs(MIRegisterGroupDMC groupDmc, IFrameDMContext frameDmc, String[] regNames) {
List<MIRegisterDMC> regDmcList = new ArrayList<MIRegisters.MIRegisterDMC>( regNames.length );
int regNo = 0;
for (String regName : regNames) {
if(regName != null && !regName.isEmpty()) {
if(frameDmc != null)
regDmcList.add(new MIRegisterDMC(this, groupDmc, frameDmc, regNo, regName));
else
regDmcList.add(new MIRegisterDMC(this, groupDmc, regNo, regName));
}
regNo++;
}
return regDmcList.toArray(new MIRegisterDMC[regDmcList.size()]);
}
/*
* Event handling section. These event handlers control the caching state of the
* register caches. This service creates several cache objects. Not all of which
* need to be flushed. These handlers maintain the state of the caches.
*/
/**
* @nooverride This method is not intended to be re-implemented or extended by clients.
* @noreference This method is not intended to be referenced by clients.
*/
@DsfServiceEventHandler
public void eventDispatched(IRunControl.IResumedDMEvent e) {
fRegisterValueCache.setContextAvailable(e.getDMContext(), false);
if (e.getReason() != StateChangeReason.STEP) {
fRegisterValueCache.reset();
}
}
/**
* @nooverride This method is not intended to be re-implemented or extended by clients.
* @noreference This method is not intended to be referenced by clients.
*/
@DsfServiceEventHandler
public void eventDispatched(
IRunControl.ISuspendedDMEvent e) {
fRegisterValueCache.setContextAvailable(e.getDMContext(), true);
fRegisterValueCache.reset();
}
/**
* @nooverride This method is not intended to be re-implemented or extended by clients.
* @noreference This method is not intended to be referenced by clients.
*/
@DsfServiceEventHandler
public void eventDispatched(final IRegisters.IRegisterChangedDMEvent e) {
fRegisterValueCache.reset();
}
/**
* @since 4.6
*/
protected void generateRegisterChangedEvent(IRegisterDMContext dmc ) {
getSession().dispatchEvent(new RegisterChangedDMEvent(dmc), getProperties());
// Fix for Bug 400840
// When one register is modified, it could affect other registers.
// To properly reflect that, we send a change for all registers.
// We cheat by pretending the group has changed, since we know there is
// only one group.
// This method can be extended by group managers to propagate the event as needed
final IRegisterGroupDMContext groupDmc = DMContexts.getAncestorOfType(dmc, IRegisterGroupDMContext.class);
if (groupDmc != null) {
IRegistersChangedDMEvent event = new IRegistersChangedDMEvent() {
@Override
public IRegisterGroupDMContext getDMContext() {
return groupDmc;
}
};
getSession().dispatchEvent(event, getProperties());
}
}
/*
* These are the public interfaces for this service.
*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#getRegisterGroups(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void getRegisterGroups(IDMContext ctx, DataRequestMonitor<IRegisterGroupDMContext[]> rm ) {
IContainerDMContext contDmc = DMContexts.getAncestorOfType(ctx, IContainerDMContext.class);
if (contDmc == null) {
rm.setStatus( new Status( IStatus.ERROR , GdbPlugin.PLUGIN_ID , INVALID_HANDLE , "Container context not found", null ) ) ; //$NON-NLS-1$
rm.done();
return;
}
//Bug 418176
//Only one group per Process (container) is supported in the implementation of this class
MIRegisterGroupDMC registerGroup = fContainerToGroupMap.get(contDmc);
if (registerGroup == null) {
registerGroup = new MIRegisterGroupDMC(this, contDmc, 0, ROOT_GROUP_NAME);
fContainerToGroupMap.put(contDmc, registerGroup);
}
MIRegisterGroupDMC[] groupDMCs = new MIRegisterGroupDMC[] { registerGroup };
rm.setData(groupDMCs) ;
rm.done() ;
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#getRegisters(org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void getRegisters(final IDMContext dmc, final DataRequestMonitor<IRegisterDMContext[]> rm) {
final MIRegisterGroupDMC groupDmc = DMContexts.getAncestorOfType(dmc, MIRegisterGroupDMC.class);
if (groupDmc == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE,
"RegisterGroup context not found", null)); //$NON-NLS-1$
rm.done();
return;
}
final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class);
if (containerDmc == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE,
"Container context not found", null)); //$NON-NLS-1$
rm.done();
return;
}
// There is only one group and its number must be 0.
if (groupDmc.getGroupNo() == 0) {
final IFrameDMContext frameDmc = DMContexts.getAncestorOfType(dmc, IFrameDMContext.class);
if (frameDmc == null) {
// The selection does not provide a specific frame, then resolve the top frame on the current thread
IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(dmc, IMIExecutionDMContext.class);
if (execDmc != null) {
IStack stackService = getServicesTracker().getService(IStack.class);
if (stackService != null) {
stackService.getTopFrame(execDmc, new ImmediateDataRequestMonitor<IStack.IFrameDMContext>(rm) {
@Override
protected void handleSuccess() {
getRegisters(getData(), groupDmc, containerDmc, rm);
}
@Override
protected void handleFailure() {
//Unable to resolve top frame on current thread.
//The thread could e.g. be in running state,
//we return register instances with no associated execution context
//i.e. unable to resolve its associated value.
getRegisters(null, groupDmc, containerDmc, rm);
}
});
return;
}
}
}
getRegisters(frameDmc, groupDmc, containerDmc, rm);
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR,
"Invalid group = " + groupDmc, null)); //$NON-NLS-1$
rm.done();
}
}
private void getRegisters(final IFrameDMContext frameDmc, final MIRegisterGroupDMC groupDmc,
IContainerDMContext containerDmc, final DataRequestMonitor<IRegisterDMContext[]> rm) {
fRegisterNameCache.execute(fCommandFactory.createMIDataListRegisterNames(containerDmc),
new ImmediateDataRequestMonitor<MIDataListRegisterNamesInfo>(rm) {
@Override
protected void handleSuccess() {
// Retrieve the register names.
String[] regNames = getData().getRegisterNames();
// If the list is empty just return empty handed.
if (regNames.length == 0) {
rm.done();
return;
}
if (frameDmc == null)
// The selection does not provide a frame or thread context,
// This can happen e.g. if a container /process is selected
// Lets provide the list of register names applicable to the selected process
// i.e. instances with only name information which can not resolve a value
rm.setData(makeRegisterDMCs(groupDmc, regNames));
else
rm.setData(makeRegisterDMCs(groupDmc, frameDmc, regNames));
rm.done();
}
});
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#getBitFields(org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void getBitFields( IDMContext regDmc , DataRequestMonitor<IBitFieldDMContext[]> rm ) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "BitField not supported", null)); //$NON-NLS-1$
rm.done();
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#writeRegister(org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext, java.lang.String, java.lang.String, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
*/
@Override
public void writeRegister(IRegisterDMContext regCtx, final String regValue, final String formatId,
final RequestMonitor rm) {
assert(regCtx instanceof MIRegisterDMC);
final MIRegisterDMC regDmc = (MIRegisterDMC) regCtx;
final IExpressions exprService = getServicesTracker().getService(IExpressions.class);
String regName = regDmc.getName();
final IExpressionDMContext exprCtxt = exprService.createExpression(regCtx, "$" + regName); //$NON-NLS-1$
final FormattedValueDMContext valueDmc = exprService.getFormattedValueContext(exprCtxt, formatId);
exprService.getFormattedExpressionValue(valueDmc, new DataRequestMonitor<FormattedValueDMData>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
if (!regValue.equals(getData().getFormattedValue()) || !valueDmc.getFormatID().equals(formatId)) {
exprService.writeExpression(exprCtxt, regValue, formatId, new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
generateRegisterChangedEvent(regDmc);
rm.done();
}
});
}// if
else {
rm.done();
}
}// handleSuccess
});
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#writeBitField(org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext, java.lang.String, java.lang.String, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
*/
@Override
public void writeBitField(IBitFieldDMContext bitFieldCtx, String bitFieldValue, String formatId, RequestMonitor rm) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Writing bit field not supported", null)); //$NON-NLS-1$
rm.done();
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#writeBitField(org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext, org.eclipse.cdt.dsf.debug.service.IRegisters.IMnemonic, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
*/
@Override
public void writeBitField(IBitFieldDMContext bitFieldCtx, IMnemonic mnemonic, RequestMonitor rm) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Writing bit field not supported", null)); //$NON-NLS-1$
rm.done();
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IFormattedValues#getAvailableFormats(org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm) {
rm.setData(new String[] { HEX_FORMAT, DECIMAL_FORMAT, OCTAL_FORMAT, BINARY_FORMAT, NATURAL_FORMAT });
rm.done();
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IFormattedValues#getFormattedValueContext(org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext, java.lang.String)
*/
@Override
public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId) {
if ( dmc instanceof MIRegisterDMC ) {
MIRegisterDMC regDmc = (MIRegisterDMC) dmc;
return( new FormattedValueDMContext( this, regDmc, formatId));
}
return null;
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#findRegisterGroup(org.eclipse.cdt.dsf.datamodel.IDMContext, java.lang.String, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void findRegisterGroup(IDMContext ctx, String name, DataRequestMonitor<IRegisterGroupDMContext> rm) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Finding a Register Group context not supported", null)); //$NON-NLS-1$
rm.done();
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#findRegister(org.eclipse.cdt.dsf.datamodel.IDMContext, java.lang.String, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void findRegister(IDMContext ctx, String name, DataRequestMonitor<IRegisterDMContext> rm) {
getRegisters(ctx, new ImmediateDataRequestMonitor<IRegisterDMContext[]>() {
@Override
protected void handleSuccess () {
IRegisterDMContext[] allRegs = getData();
// in all registers found, look for one with the name we seek
for (int i = 0; i < allRegs.length; i++) {
if (allRegs[i] instanceof MIRegisterDMC) {
if (name.equals(((MIRegisterDMC)allRegs[i]).getName())) {
// found it
rm.done(allRegs[i]);
return;
}
}
}
// register was not found
rm.done(new Status(IStatus.WARNING, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown register name", null)); //$NON-NLS-1$
return;
}
});
}
/*
* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IRegisters#findBitField(org.eclipse.cdt.dsf.datamodel.IDMContext, java.lang.String, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void findBitField(IDMContext ctx, String name, DataRequestMonitor<IBitFieldDMContext> rm) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Finding a Register Group context not supported", null)); //$NON-NLS-1$
rm.done();
}
/**
* {@inheritDoc}
* @since 1.1
*/
@Override
public void flushCache(IDMContext context) {
fRegisterNameCache.reset(context);
fRegisterValueCache.reset(context);
}
}