/******************************************************************************* * Copyright (c) 2007, 2015 Ericsson 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: * Ericsson - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.tests.dsf.breakpoints; import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import org.eclipse.cdt.core.IAddress; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Immutable; 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.IBreakpoints; import org.eclipse.cdt.dsf.service.AbstractDsfService; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.tests.dsf.DsfTestPlugin; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.model.IBreakpoint; import org.osgi.framework.BundleContext; /** * Initial breakpoint service implementation. * Implements the IBreakpoints interface. */ public class DsfTestBreakpoints extends AbstractDsfService implements IBreakpoints { public static final String ATTR_DEBUGGER_PREFIX = DsfTestBreakpoint.DSF_TEST_BREAKPOINT_MODEL_ID + ".debugger."; public static final String ATTR_ENABLED = ATTR_DEBUGGER_PREFIX + "enabled"; public static final String ATTR_TRANSLATED = ATTR_DEBUGGER_PREFIX + "enabled"; public static final String ATTR_SUB_ID = ATTR_DEBUGGER_PREFIX + "subId"; @Immutable public static class BreakpointsTargetDMContext extends AbstractDMContext implements IBreakpointsTargetDMContext { private static int fIdCounter = 1; public final Integer fId = fIdCounter++; BreakpointsTargetDMContext (String sessionId) { super(sessionId, DMContexts.EMPTY_CONTEXTS_ARRAY); } @Override public boolean equals(Object obj) { return baseEquals(obj) && (fId.equals(((BreakpointsTargetDMContext) obj).fId)); } @Override public int hashCode() { return baseHashCode() + fId.hashCode() ; } @Override public String toString() { return "breakpointsTarget(" + fId + ")"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ } } /** * Context representing a PDA line breakpoint. In PDA debugger, since there is only * one file being debugged at a time, a breakpoint is uniquely identified using the * line number only. */ @Immutable public static class BreakpointDMContext extends AbstractDMContext implements IBreakpointDMContext { public final Integer fId; public final Integer fSubId; public BreakpointDMContext(String sessionId, BreakpointsTargetDMContext commandControlCtx, Integer id, Integer subId) { super(sessionId, new IDMContext[] { commandControlCtx }); fId = id; fSubId = subId; } @Override public boolean equals(Object obj) { return baseEquals(obj) && (fId.equals(((BreakpointDMContext) obj).fId)) && (fSubId.equals(((BreakpointDMContext) obj).fSubId)); } @Override public int hashCode() { return baseHashCode() + fId.hashCode() + fSubId.hashCode(); } @Override public String toString() { return baseToString() + ".breakpoint(" + fId + "-" + fSubId + ")"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ } } @Immutable public static class BreakpointDMData implements IBreakpointDMData { public final Map<String, Object> fAttributes; public BreakpointDMData(Map<String, Object> attributes) { fAttributes = Collections.unmodifiableMap( new HashMap<String, Object>(attributes) ); } @Override public IAddress[] getAddresses() { return null; } @Override public String getBreakpointType() { return null; } @Override public String getFileName() { return null; } @Override public int getLineNumber() { return 0; } @Override public String getFunctionName() { return null; } @Override public String getCondition() { return null; } @Override public int getIgnoreCount() { return 0; } @Override public String getExpression() { return null; } @Override public boolean isEnabled() { return (Boolean)getAttributes().get(ATTR_ENABLED); } public Map<String, Object> getAttributes() { return fAttributes; } } public static class BreakpointsChangedEvent implements IBreakpointsChangedEvent { public final BreakpointDMContext fBreakpoint; public final IBreakpointDMContext [] fBreakpointArray; BreakpointsChangedEvent (BreakpointDMContext bp) { fBreakpoint = bp; fBreakpointArray = new IBreakpointDMContext[] { bp }; } @Override public IBreakpointsTargetDMContext getDMContext() { return DMContexts.getAncestorOfType(fBreakpoint, IBreakpointsTargetDMContext.class); } @Override public IBreakpointDMContext[] getBreakpoints() { return fBreakpointArray; } } public static class BreakpointsAddedEvent extends BreakpointsChangedEvent implements IBreakpointsAddedEvent { BreakpointsAddedEvent(BreakpointDMContext bp) { super(bp); } } public static class BreakpointsRemovedEvent extends BreakpointsChangedEvent implements IBreakpointsRemovedEvent { BreakpointsRemovedEvent(BreakpointDMContext bp) { super(bp); } } public static class BreakpointsUpdatedEvent extends BreakpointsChangedEvent implements IBreakpointsUpdatedEvent { BreakpointsUpdatedEvent(BreakpointDMContext bp) { super(bp); } } // Breakpoints currently installed private Map<BreakpointDMContext, BreakpointDMData> fBreakpoints = new HashMap<BreakpointDMContext, BreakpointDMData>(); /** * The service constructor * * @param session The debugging session this service belongs to. */ public DsfTestBreakpoints(DsfSession session) { super(session); } @Override public void initialize(final RequestMonitor rm) { super.initialize(new RequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { doInitialize(rm); } }); } private void doInitialize(final RequestMonitor rm) { // Register this service register(new String[] { IBreakpoints.class.getName(), DsfTestBreakpoints.class.getName() }, new Hashtable<String, String>()); rm.done(); } @Override public void shutdown(final RequestMonitor rm) { unregister(); rm.done(); } @Override protected BundleContext getBundleContext() { return DsfTestPlugin.getBundleContext(); } @Override public void getBreakpoints(final IBreakpointsTargetDMContext context, final DataRequestMonitor<IBreakpointDMContext[]> rm) { // Validate the context // TODO: check the target context // if (!fCommandControl.getContext().equals(context)) { // DsfTestPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoints target context"); // return; // } rm.setData(fBreakpoints.keySet().toArray(new IBreakpointDMContext[fBreakpoints.size()])); rm.done(); } @Override public void getBreakpointDMData(IBreakpointDMContext dmc, DataRequestMonitor<IBreakpointDMData> rm) { DsfTestPlugin.failRequest(rm, NOT_SUPPORTED, "Retrieving breakpoint data is not supported"); } @Override public void insertBreakpoint(IBreakpointsTargetDMContext context, Map<String, Object> attributes, DataRequestMonitor<IBreakpointDMContext> rm) { Boolean enabled = (Boolean)attributes.get(IBreakpoint.ENABLED); if (enabled != null && !enabled.booleanValue()) { // If the breakpoint is disabled, just fail the request. DsfTestPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint is disabled"); } else { BreakpointsTargetDMContext targetCtx = DMContexts.getAncestorOfType(context, BreakpointsTargetDMContext.class); if (targetCtx != null) { doInsertBreakpoint(targetCtx, attributes, rm); } else { DsfTestPlugin.failRequest(rm, INVALID_HANDLE, "Unknown breakpoint type"); } } } private void doInsertBreakpoint(BreakpointsTargetDMContext targetCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm) { // Retrieve the id Integer id = (Integer)attributes.get(DsfTestBreakpoint.ATTR_ID); if (id == null) { DsfTestPlugin.failRequest(rm, REQUEST_FAILED, "No ID specified"); return; } Integer subId = (Integer)attributes.get(ATTR_SUB_ID); if (subId == null) { DsfTestPlugin.failRequest(rm, REQUEST_FAILED, "No Sub ID specified"); return; } // Create a new breakpoint context object and check that it's not // installed already. PDA can only track a single breakpoint at a // given line, attempting to set the second breakpoint should fail. final BreakpointDMContext breakpointCtx = new BreakpointDMContext(getSession().getId(), targetCtx, id, subId); if (fBreakpoints.containsKey(breakpointCtx)) { DsfTestPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already set"); return; } // Add the new breakpoint context to the list of known breakpoints. // Adding it here, before the set command is completed will prevent // a possibility of a second breakpoint being installed in the same // location while this breakpoint is being processed. It will also // allow the breakpoint to be removed or updated even while it is // still being processed here. fBreakpoints.put(breakpointCtx, new BreakpointDMData(attributes)); rm.setData(breakpointCtx); getSession().dispatchEvent(new BreakpointsAddedEvent(breakpointCtx), getProperties()); } @Override public void removeBreakpoint(IBreakpointDMContext bpCtx, RequestMonitor rm) { if (!fBreakpoints.containsKey(bpCtx)) { DsfTestPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already removed"); return; } if (bpCtx instanceof BreakpointDMContext) { if ( fBreakpoints.remove(bpCtx) == null ) { DsfTestPlugin.failRequest(rm, INVALID_STATE, "Breakpoint does not exist"); } else { getSession().dispatchEvent(new BreakpointsRemovedEvent((BreakpointDMContext)bpCtx), getProperties()); } rm.done(); } else { rm.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid breakpoint type", null )); rm.done(); } } @Override public void updateBreakpoint(final IBreakpointDMContext bpCtx, Map<String, Object> attributes, final RequestMonitor rm) { if (!fBreakpoints.containsKey(bpCtx)) { DsfTestPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint not installed"); return; } for (String attribute : attributes.keySet()) { if (!DsfTestBreakpoint.ATTR_UPDATABLE.equals(attribute)) { DsfTestPlugin.failRequest(rm, REQUEST_FAILED, "Attribute cannot be updated"); return; } } if (bpCtx instanceof BreakpointDMContext) { Map<String, Object> newAttrs = new HashMap<String, Object>(fBreakpoints.get(bpCtx).getAttributes()); newAttrs.putAll(attributes); fBreakpoints.put((BreakpointDMContext)bpCtx, new BreakpointDMData(newAttrs)); getSession().dispatchEvent(new BreakpointsRemovedEvent((BreakpointDMContext)bpCtx), getProperties()); } else { DsfTestPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoint type"); } } }