/******************************************************************************* * Copyright (c) 2008, 2009 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 *******************************************************************************/ package org.eclipse.cdt.examples.dsf.pda.service; import java.math.BigInteger; import java.util.Hashtable; import java.util.Map; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; 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.IRegisters; import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext; import org.eclipse.cdt.dsf.debug.service.command.CommandCache; import org.eclipse.cdt.dsf.debug.service.command.IEventListener; import org.eclipse.cdt.dsf.service.AbstractDsfService; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.examples.dsf.pda.PDAPlugin; import org.eclipse.cdt.examples.dsf.pda.service.commands.PDABitField; import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAGroupsCommand; import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAListResult; import org.eclipse.cdt.examples.dsf.pda.service.commands.PDARegister; import org.eclipse.cdt.examples.dsf.pda.service.commands.PDARegistersCommand; import org.eclipse.cdt.examples.dsf.pda.service.commands.PDARegistersCommandResult; import org.osgi.framework.BundleContext; /** * */ public class PDARegisters extends AbstractDsfService implements IRegisters, IEventListener, ICachingService { private static class RegisterGroupDMContext extends AbstractDMContext implements IRegisterGroupDMContext { final private String fName; public RegisterGroupDMContext(String sessionId, PDAVirtualMachineDMContext dmc, String groupName) { super(sessionId, new IDMContext[] { dmc }); fName = groupName; } @Override public boolean equals(Object other) { return ((super.baseEquals(other)) && (((RegisterGroupDMContext) other).fName.equals(fName))); } @Override public int hashCode() { return super.baseHashCode() + fName.hashCode(); } @Override public String toString() { return baseToString() + ".group[" + fName + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ } private static class RegisterDMContext extends AbstractDMContext implements IRegisterDMContext { final private PDARegister fRegister; public RegisterDMContext(String sessionId, PDAThreadDMContext thread, RegisterGroupDMContext group, PDARegister reg) { super(sessionId, new IDMContext[] { thread, group }); fRegister = reg; } @Override public boolean equals(Object other) { return ((super.baseEquals(other)) && (((RegisterDMContext) other).fRegister.fName.equals(fRegister.fName))); } @Override public int hashCode() { return super.baseHashCode() + fRegister.fName.hashCode(); } @Override public String toString() { return baseToString() + ".register[" + fRegister.fName + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ } /* * Support class used to construct BitField DMCs. */ private static class BitFieldDMContext extends AbstractDMContext implements IBitFieldDMContext { final private PDABitField fBitField; public BitFieldDMContext(String sessionId, RegisterDMContext reg, PDABitField bitField) { super(sessionId, new IDMContext[] { reg }); fBitField = bitField; } /* * Required common manipulation routines. */ @Override public boolean equals(Object other) { if (other instanceof BitFieldDMContext) { BitFieldDMContext dmc = (BitFieldDMContext) other; return( (super.baseEquals(other)) && (dmc.fBitField.fName.equals(fBitField.fName))); } else { return false; } } @Override public int hashCode() { return super.baseHashCode() + fBitField.fName.hashCode(); } @Override public String toString() { return baseToString() + ".bitfield[" + fBitField.fName + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ } private static class RegisterGroupDMData implements IRegisterGroupDMData { final private String fName; public RegisterGroupDMData(String name) { fName = name; } public String getName() { return fName; } public String getDescription() { return "Description of the " + fName + " register group"; } } private static class RegisterDMData implements IRegisterDMData { final private PDARegister fRegister; public RegisterDMData(PDARegister reg) { fRegister = reg; } public boolean isReadable() { return true; } public boolean isReadOnce() { return false; } public boolean isWriteable() { return fRegister.fWritable; } public boolean isWriteOnce() { return false; } public boolean hasSideEffects() { return false; } public boolean isVolatile() { return true; } public boolean isFloat() { return false; } public String getName() { return fRegister.fName; } public String getDescription() { return "Description of the " + fRegister.fName + " register"; } } private static class Mnemonic implements IMnemonic { Mnemonic(String name, String value, int numBits) { fName = name; fValue = new BigInteger(value); fNumBits = numBits; } final private String fName; final private BigInteger fValue; final private int fNumBits; public String getShortName() { return fName; } public String getLongName() { return fName; } public BigInteger getValue() { return fValue; } public int getBitCount() { return fNumBits; } @Override public boolean equals( Object element ) { if ( element instanceof Mnemonic ) { Mnemonic mnem = (Mnemonic) element; return ( mnem.fName.equals( fName ) ) && ( mnem.fValue.equals( fValue ) ) && ( mnem.fNumBits == fNumBits ); } return false ; } } private class BitFieldDMData implements IBitFieldDMData { final private PDABitField fBitField; final private IBitGroup[] fBitGroups; final private Mnemonic[] fMnemonics; final private BigInteger fValue; final private Mnemonic fMnemonicValue; public BitFieldDMData(PDABitField bitField, String value) { fBitField = bitField; fValue = new BigInteger(value); fBitGroups = new IBitGroup[] { new IBitGroup() { public int startBit() { return fBitField.fOffset; } public int bitCount() { return fBitField.fCount; } } }; fMnemonics = new Mnemonic[fBitField.fMnemonics.size()]; Mnemonic mnemonicValue = null; int i = 0; for (Map.Entry<String, String> mnemonicEntry : fBitField.fMnemonics.entrySet()) { fMnemonics[i] = new Mnemonic(mnemonicEntry.getKey(), mnemonicEntry.getValue(), fBitField.fCount); if (fValue.equals(fMnemonics[i].fValue)) { mnemonicValue = fMnemonics[i]; } i++; } fMnemonicValue = mnemonicValue; } public IBitGroup[] getBitGroup() { return fBitGroups; } public IMnemonic[] getMnemonics() { return fMnemonics; } public boolean isZeroBasedNumbering() { return true; } public boolean isZeroBitLeftMost() { return true; } public boolean isReadable() { return true; } public boolean isReadOnce() { return false; } public boolean isWriteable() { return true; } public boolean isWriteOnce() { return false; } public boolean hasSideEffects() { return false; } public boolean isFloat() { return false; } public String getName() { return fBitField.fName; } public String getDescription() { return "Description of the " + fBitField.fName + " bit field"; } public IMnemonic getCurrentMnemonicValue() { return fMnemonicValue; } } private static class RegisterChangedDMEvent extends AbstractDMEvent<IRegisterDMContext> implements IRegisterChangedDMEvent { RegisterChangedDMEvent(IRegisterDMContext registerDmc) { super(registerDmc); } } private PDACommandControl fCommandControl; private PDAExpressions fExpressions; private CommandCache fNamesCache; public PDARegisters(DsfSession session) { super(session); } @Override protected BundleContext getBundleContext() { return PDAPlugin.getBundleContext(); } @Override public void initialize(final RequestMonitor requestMonitor) { super.initialize( new RequestMonitor(getExecutor(), requestMonitor) { @Override protected void handleSuccess() { doInitialize(requestMonitor); }}); } private void doInitialize(RequestMonitor requestMonitor) { fCommandControl = getServicesTracker().getService(PDACommandControl.class); fExpressions = getServicesTracker().getService(PDAExpressions.class); // Create the cache to store the register definitions. This cache // only needs to be reset upon the "registers" event and is available // all the time. fNamesCache = new CommandCache(getSession(), fCommandControl); fNamesCache.setContextAvailable(fCommandControl.getContext(), true); // Add the register service as a listener to PDA events, to catch // the "registers" events from the command control. fCommandControl.addEventListener(this); // 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(), PDARegisters.class.getName()}, new Hashtable<String,String>()); requestMonitor.done(); } @Override public void shutdown(RequestMonitor requestMonitor) { unregister(); fCommandControl.removeEventListener(this); getSession().removeServiceEventListener(this); super.shutdown(requestMonitor); } public void getRegisterGroups(IDMContext ctx, final DataRequestMonitor<IRegisterGroupDMContext[]> rm ) { final PDAVirtualMachineDMContext dmc = DMContexts.getAncestorOfType(ctx, PDAVirtualMachineDMContext.class); if (dmc == null) { PDAPlugin.failRequest(rm, INVALID_HANDLE, "Container context not found"); //$NON-NLS-1$ return; } fNamesCache.execute( new PDAGroupsCommand(dmc), new DataRequestMonitor<PDAListResult>(getExecutor(), rm) { @Override protected void handleSuccess() { IRegisterGroupDMContext[] groups = new IRegisterGroupDMContext[getData().fValues.length]; for (int i = 0; i < getData().fValues.length; i++) { groups[i] = new RegisterGroupDMContext(getSession().getId(), dmc, getData().fValues[i]); } rm.setData(groups); rm.done(); }; }); } public void getRegisters(final IDMContext ctx, final DataRequestMonitor<IRegisterDMContext[]> rm) { final PDAThreadDMContext execDmc = DMContexts.getAncestorOfType(ctx, PDAThreadDMContext.class); if ( execDmc == null ) { PDAPlugin.failRequest(rm, INVALID_HANDLE , "Thread context not found"); //$NON-NLS-1$ return; } final RegisterGroupDMContext groupDmc = DMContexts.getAncestorOfType(ctx, RegisterGroupDMContext.class); if ( groupDmc == null ) { PDAPlugin.failRequest(rm, INVALID_HANDLE , "Group context not found"); //$NON-NLS-1$ return; } fNamesCache.execute( new PDARegistersCommand(execDmc, groupDmc != null ? groupDmc.fName : null), new DataRequestMonitor<PDARegistersCommandResult>(getExecutor(), rm) { @Override protected void handleSuccess() { IRegisterDMContext[] groups = new IRegisterDMContext[getData().fRegisters.length]; for (int i = 0; i < getData().fRegisters.length; i++) { groups[i] = new RegisterDMContext(getSession().getId(), execDmc, groupDmc, getData().fRegisters[i]); } rm.setData(groups); rm.done(); }; }); } public void getBitFields( IDMContext dmc , DataRequestMonitor<IBitFieldDMContext[]> rm ) { RegisterDMContext registerDmc = DMContexts.getAncestorOfType(dmc, RegisterDMContext.class); if ( registerDmc == null ) { PDAPlugin.failRequest(rm,INVALID_HANDLE, "No register in context: " + dmc) ; //$NON-NLS-1$ return; } PDABitField[] bitFields = registerDmc.fRegister.fBitFields; BitFieldDMContext[] bitFieldDMCs = new BitFieldDMContext[bitFields.length]; for (int i = 0; i < bitFields.length; i++) { bitFieldDMCs[i] = new BitFieldDMContext(getSession().getId(), registerDmc, bitFields[i]); } rm.setData(bitFieldDMCs) ; rm.done(); } public void writeRegister(final IRegisterDMContext regCtx, String regValue, String formatId, final RequestMonitor rm) { if (regCtx instanceof RegisterDMContext) { IExpressionDMContext exprCtx = createRegisterExpressionDmc( (RegisterDMContext)regCtx ); fExpressions.writeExpression( exprCtx, regValue, formatId, false, new RequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { generateRegisterChangedEvent( (RegisterDMContext)regCtx ); rm.done(); } }); } else { PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$ } } public void writeBitField(final IBitFieldDMContext bitFieldCtx, String bitFieldValue, String formatId, final RequestMonitor rm) { if (bitFieldCtx instanceof BitFieldDMContext) { IExpressionDMContext exprCtx = createBitFieldExpressionDmc( (BitFieldDMContext)bitFieldCtx ); fExpressions.writeExpression( exprCtx, bitFieldValue, formatId, false, new RequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { generateRegisterChangedEvent( DMContexts.getAncestorOfType(bitFieldCtx, RegisterDMContext.class) ); rm.done(); } }); } else { PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$ } } public void writeBitField(IBitFieldDMContext bitFieldCtx, IMnemonic mnemonic, RequestMonitor rm) { if (mnemonic instanceof Mnemonic) { writeBitField(bitFieldCtx, ((Mnemonic)mnemonic).fValue.toString(), NATURAL_FORMAT, rm); } else { PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid mnemonic"); //$NON-NLS-1$ } } public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm) { IExpressionDMContext exprCtx = null; if ( dmc instanceof RegisterDMContext ) { exprCtx = createRegisterExpressionDmc((RegisterDMContext)dmc); } else if ( dmc instanceof BitFieldDMContext ) { exprCtx = createBitFieldExpressionDmc((BitFieldDMContext)dmc); } if (exprCtx != null) { fExpressions.getAvailableFormats(exprCtx, rm); } else { throw new IllegalArgumentException("Invalid register/bit field context " + dmc); } } public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId) { IExpressionDMContext exprCtx = null; if ( dmc instanceof RegisterDMContext ) { exprCtx = createRegisterExpressionDmc((RegisterDMContext)dmc); } else if ( dmc instanceof BitFieldDMContext ) { exprCtx = createBitFieldExpressionDmc((BitFieldDMContext)dmc); } if (exprCtx != null) { return fExpressions.getFormattedValueContext(exprCtx, formatId); } else { throw new IllegalArgumentException("Invalid register/bit field context " + dmc); } } public void findRegisterGroup(IDMContext ctx, String name, DataRequestMonitor<IRegisterGroupDMContext> rm) { PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Finding context not supported"); //$NON-NLS-1$ } public void findRegister(IDMContext ctx, String name, DataRequestMonitor<IRegisterDMContext> rm) { PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Finding context not supported"); //$NON-NLS-1$ } public void findBitField(IDMContext ctx, String name, DataRequestMonitor<IBitFieldDMContext> rm) { PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Finding context not supported"); //$NON-NLS-1$ } public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor<FormattedValueDMData> rm) { fExpressions.getFormattedExpressionValue(dmc, rm); } public void getRegisterGroupData(IRegisterGroupDMContext regGroupDmc, DataRequestMonitor<IRegisterGroupDMData> rm) { if (regGroupDmc instanceof RegisterGroupDMContext) { rm.setData(new RegisterGroupDMData( ((RegisterGroupDMContext)regGroupDmc).fName )); rm.done(); } else { PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$ } } public void getRegisterData(IRegisterDMContext regDmc , DataRequestMonitor<IRegisterDMData> rm) { if (regDmc instanceof RegisterDMContext) { rm.setData(new RegisterDMData( ((RegisterDMContext)regDmc).fRegister )); rm.done(); } else { PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$ } } public void getBitFieldData(IBitFieldDMContext dmc, final DataRequestMonitor<IBitFieldDMData> rm) { if ( !(dmc instanceof BitFieldDMContext) ) { PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$ } final BitFieldDMContext bitFieldDmc = (BitFieldDMContext) dmc; IExpressionDMContext bitFieldExprDmc = createBitFieldExpressionDmc(bitFieldDmc); FormattedValueDMContext formattedBitFieldDmc = fExpressions.getFormattedValueContext(bitFieldExprDmc, NATURAL_FORMAT); fExpressions.getFormattedExpressionValue( formattedBitFieldDmc, new DataRequestMonitor<FormattedValueDMData>(getExecutor(), rm) { @Override protected void handleSuccess() { rm.setData(new BitFieldDMData(bitFieldDmc.fBitField, getData().getFormattedValue())); rm.done(); } }); } private IExpressionDMContext createRegisterExpressionDmc(RegisterDMContext dmc) { return fExpressions.createExpression(dmc, "$" + dmc.fRegister.fName); } private IExpressionDMContext createBitFieldExpressionDmc(BitFieldDMContext dmc) { RegisterDMContext regDmc = DMContexts.getAncestorOfType(dmc, RegisterDMContext.class); return fExpressions.createExpression(dmc, "$" + regDmc.fRegister.fName + "." + dmc.fBitField.fName); } @DsfServiceEventHandler public void eventDispatched(IRunControl.IResumedDMEvent e) { } @DsfServiceEventHandler public void eventDispatched( IRunControl.ISuspendedDMEvent e) { } @DsfServiceEventHandler public void eventDispatched(final IRegisters.IRegisterChangedDMEvent e) { } private void generateRegisterChangedEvent(RegisterDMContext dmc ) { getSession().dispatchEvent(new RegisterChangedDMEvent(dmc), getProperties()); } public void eventReceived(Object output) { if (!(output instanceof String)) return; if ("registers".equals(output)) { fNamesCache.reset(); } } public void flushCache(IDMContext context) { fExpressions.flushCache(context); } }