blob: 5b539f2aca5847e557348e2d6c6d8afdfef8147e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2016 Ericsson and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Ericsson - Initial API and implementation
* Mike Wrighton (Mentor Graphics) - Formatting address for a watchpoint (Bug 376105)
* Marc Khouzam (Ericsson) - Support for dynamic printf (Bug 400628)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
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.Immutable;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Sequence.Step;
import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
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.IBreakpoints;
import org.eclipse.cdt.dsf.debug.service.IBreakpointsExtension;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
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.events.MIWatchpointScopeEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.CLICatchInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MITuple;
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.Platform;
import org.eclipse.core.runtime.Status;
import org.osgi.framework.BundleContext;
/**
* Initial breakpoint service implementation.
* Implements the IBreakpoints interface.
*/
public class MIBreakpoints extends AbstractDsfService implements IBreakpointsExtension, IMIBreakpointPathAdjuster {
/**
* Breakpoint attributes markers used in the map parameters of insert/updateBreakpoint().
* All are optional with the possible exception of TYPE. It is the responsibility of the
* service to ensure that the set of attributes provided is sufficient to create/update
* a valid breakpoint on the back-end.
*/
public static final String PREFIX = "org.eclipse.cdt.dsf.debug.breakpoint"; //$NON-NLS-1$
// General markers
public static final String BREAKPOINT_TYPE = PREFIX + ".type"; //$NON-NLS-1$
public static final String BREAKPOINT = "breakpoint"; //$NON-NLS-1$
public static final String WATCHPOINT = "watchpoint"; //$NON-NLS-1$
public static final String CATCHPOINT = "catchpoint"; //$NON-NLS-1$
/** @since 3.0 */
public static final String TRACEPOINT = "tracepoint"; //$NON-NLS-1$
/** @since 4.4 */
public static final String DYNAMICPRINTF = "dynamicPrintf"; //$NON-NLS-1$
// Basic set of breakpoint attribute markers
public static final String FILE_NAME = PREFIX + ".fileName"; //$NON-NLS-1$
public static final String LINE_NUMBER = PREFIX + ".lineNumber"; //$NON-NLS-1$
public static final String FUNCTION = PREFIX + ".function"; //$NON-NLS-1$
public static final String ADDRESS = PREFIX + ".address"; //$NON-NLS-1$
public static final String CONDITION = PREFIX + ".condition"; //$NON-NLS-1$
public static final String IGNORE_COUNT = PREFIX + ".ignoreCount"; //$NON-NLS-1$
/** @since 3.0 */
public static final String PASS_COUNT = PREFIX + ".passCount"; //$NON-NLS-1$
public static final String IS_ENABLED = PREFIX + ".isEnabled"; //$NON-NLS-1$
/** @since 3.0 */
public static final String COMMANDS = PREFIX + ".commands"; //$NON-NLS-1$
// Basic set of watchpoint attribute markers
public static final String EXPRESSION = PREFIX + ".expression"; //$NON-NLS-1$
public static final String READ = PREFIX + ".read"; //$NON-NLS-1$
public static final String WRITE = PREFIX + ".write"; //$NON-NLS-1$
/** @since 5.3 */
public static final String RANGE = PREFIX + ".range"; //$NON-NLS-1$
/** @since 5.3 */
public static final String MEMSPACE = PREFIX + ".memoryspace"; //$NON-NLS-1$
// Catchpoint properties
// DynamicPrintf properties
/** @since 4.4 */
public static final String PRINTF_STRING = PREFIX + ".printf_string"; //$NON-NLS-1$
/**
* Property that indicates the kind of catchpoint (.e.g, fork call, C++
* exception throw). Value is the gdb keyword associated with that type, as
* listed in 'help catch'.
*
* @since 3.0
*/
public static final String CATCHPOINT_TYPE = PREFIX + ".catchpoint_type"; //$NON-NLS-1$
/**
* Property that holds arguments for the catchpoint. Value is an array of
* Strings. Never null, but may be empty collection, as most catchpoints are
* argument-less.
*
* @since 3.0
*/
public static final String CATCHPOINT_ARGS = PREFIX + ".catchpoint_args"; //$NON-NLS-1$
// Services
private ICommandControl fConnection;
private IMIRunControl fRunControl;
private CommandFactory fCommandFactory;
// Service breakpoints tracking
// The breakpoints are stored per context and keyed on the back-end breakpoint reference
private Map<IBreakpointsTargetDMContext, Map<String, MIBreakpointDMData>> fBreakpoints = new HashMap<>();
/**
* Map tracking which threads are currently suspended on a breakpoint.
* @since 3.0
*/
private Map<IExecutionDMContext, IBreakpointDMContext[]> fBreakpointHitMap = new HashMap<>();
/**
* Returns a map of existing breakpoints for the specified context
*
* @since 3.0
*/
protected Map<String, MIBreakpointDMData> getBreakpointMap(IBreakpointsTargetDMContext ctx) {
return fBreakpoints.get(ctx);
}
/**
* Create an empty breakpoint map and store it with the specific context.
*
* @return The newly created empty map.
*
* @since 3.0
*/
protected Map<String, MIBreakpointDMData> createNewBreakpointMap(IBreakpointsTargetDMContext ctx) {
Map<String, MIBreakpointDMData> map = new HashMap<>();
fBreakpoints.put(ctx, map);
return map;
}
/**
* Create a new effective breakpoint data object
*
* @param breakpoint
* backend breakpoint to create DSF object from
* @return breakpoint data object
* @since 5.3
*/
@ThreadSafe
public MIBreakpointDMData createMIBreakpointDMData(MIBreakpoint breakpoint) {
@SuppressWarnings("deprecation")
MIBreakpointDMData data = new MIBreakpointDMData(breakpoint);
return data;
}
/**
* Create a new MI breakpoint
*
* @param tuple
* from backend communication
* @return breakpoint
* @since 5.3
*/
@ThreadSafe
public MIBreakpoint createMIBreakpoint(MITuple tuple) {
return new MIBreakpoint(tuple);
}
// Error messages
/** @since 3.0 */
public static final String NULL_STRING = ""; //$NON-NLS-1$
/** @since 3.0 */
public static final String UNKNOWN_EXECUTION_CONTEXT = "Unknown execution context"; //$NON-NLS-1$
/** @since 3.0 */
public static final String UNKNOWN_BREAKPOINT_CONTEXT = "Unknown breakpoint context"; //$NON-NLS-1$
/** @since 3.0 */
public static final String UNKNOWN_BREAKPOINT_TYPE = "Unknown breakpoint type"; //$NON-NLS-1$
/** @since 3.0 */
public static final String UNKNOWN_BREAKPOINT = "Unknown breakpoint"; //$NON-NLS-1$
/** @since 3.0 */
public static final String BREAKPOINT_INSERTION_FAILURE = "Breakpoint insertion failure"; //$NON-NLS-1$
/** @since 3.0 */
public static final String WATCHPOINT_INSERTION_FAILURE = "Watchpoint insertion failure"; //$NON-NLS-1$
/** @since 3.0 */
public static final String INVALID_CONDITION = "Invalid condition"; //$NON-NLS-1$
/** @since 3.0 */
public static final String TRACEPOINT_INSERTION_FAILURE = "Tracepoint insertion failure"; //$NON-NLS-1$
/** @since 4.4 */
public static final String DYNAMIC_PRINTF_INSERTION_FAILURE = "Dynamic printf insertion failure"; //$NON-NLS-1$
/** @since 3.0 */
public static final String INVALID_BREAKPOINT_TYPE = "Invalid breakpoint type"; //$NON-NLS-1$
/** @since 3.0 */
public static final String CATCHPOINT_INSERTION_FAILURE = "Catchpoint insertion failure"; //$NON-NLS-1$
///////////////////////////////////////////////////////////////////////////
// Breakpoint Events
///////////////////////////////////////////////////////////////////////////
public class BreakpointsChangedEvent extends AbstractDMEvent<IBreakpointsTargetDMContext>
implements IBreakpointsChangedEvent {
private IBreakpointDMContext[] fEventBreakpoints;
public BreakpointsChangedEvent(IBreakpointDMContext bp) {
super(DMContexts.getAncestorOfType(bp, IBreakpointsTargetDMContext.class));
fEventBreakpoints = new IBreakpointDMContext[] { bp };
}
@Override
public IBreakpointDMContext[] getBreakpoints() {
return fEventBreakpoints;
}
}
public class BreakpointAddedEvent extends BreakpointsChangedEvent implements IBreakpointsAddedEvent {
public BreakpointAddedEvent(IBreakpointDMContext context) {
super(context);
}
}
public class BreakpointUpdatedEvent extends BreakpointsChangedEvent implements IBreakpointsUpdatedEvent {
public BreakpointUpdatedEvent(IBreakpointDMContext context) {
super(context);
}
}
public class BreakpointRemovedEvent extends BreakpointsChangedEvent implements IBreakpointsRemovedEvent {
public BreakpointRemovedEvent(IBreakpointDMContext context) {
super(context);
}
}
///////////////////////////////////////////////////////////////////////////
// IBreakpointDMContext
// Used to hold the back-end breakpoint references. The reference can then
// be used to get the actual DsfMIBreakpoint.
///////////////////////////////////////////////////////////////////////////
@Immutable
public static final class MIBreakpointDMContext extends AbstractDMContext implements IBreakpointDMContext {
// The breakpoint reference
private final String fReference;
/**
* @param service the Breakpoint service
* @param parents the parent contexts
* @param reference the DsfMIBreakpoint reference
*
* @since 5.0
*/
public MIBreakpointDMContext(MIBreakpoints service, IDMContext[] parents, String reference) {
this(service.getSession().getId(), parents, reference);
}
/**
* @param sessionId session ID
* @param parents the parent contexts
* @param reference the DsfMIBreakpoint reference
*
* @since 5.0
*/
public MIBreakpointDMContext(String sessionId, IDMContext[] parents, String reference) {
super(sessionId, parents);
fReference = reference;
}
/**
* @returns a reference to the breakpoint
* @see org.eclipse.cdt.dsf.debug.service.IBreakpoints.IDsfBreakpointDMContext#getReference()
* @since 5.0
*/
public String getReference() {
return fReference;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof MIBreakpointDMContext)) {
return false;
}
return baseEquals(obj) && (fReference.equals(((MIBreakpointDMContext) obj).fReference));
}
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#hashCode()
*/
@Override
public int hashCode() {
return baseHashCode() + fReference.hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return baseToString() + ".reference(" + fReference + ")"; //$NON-NLS-1$//$NON-NLS-2$*/
}
}
///////////////////////////////////////////////////////////////////////////
// AbstractDsfService
///////////////////////////////////////////////////////////////////////////
/**
* The service constructor
*
* @param session The debugging session
*/
public MIBreakpoints(DsfSession session) {
super(session);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.service.AbstractDsfService#initialize(org.eclipse.cdt.dsf.concurrent.RequestMonitor)
*/
@Override
public void initialize(final RequestMonitor rm) {
super.initialize(new ImmediateRequestMonitor(rm) {
@Override
protected void handleSuccess() {
doInitialize(rm);
}
});
}
/*
* Asynchronous service initialization
*/
private void doInitialize(final RequestMonitor rm) {
// Get the services references
fConnection = getServicesTracker().getService(ICommandControl.class);
fRunControl = getServicesTracker().getService(IMIRunControl.class);
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
// Register for the useful events
getSession().addServiceEventListener(this, null);
// Register this service
register(new String[] { IBreakpoints.class.getName(), IBreakpointsExtension.class.getName(),
MIBreakpoints.class.getName() }, new Hashtable<String, String>());
rm.done();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.service.AbstractDsfService#shutdown(org.eclipse.cdt.dsf.concurrent.RequestMonitor)
*/
@Override
public void shutdown(final RequestMonitor rm) {
unregister();
getSession().removeServiceEventListener(this);
super.shutdown(rm);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.service.AbstractDsfService#getBundleContext()
*/
@Override
protected BundleContext getBundleContext() {
return GdbPlugin.getBundleContext();
}
///////////////////////////////////////////////////////////////////////////
// IServiceEventListener
///////////////////////////////////////////////////////////////////////////
/**
* This method is left for API compatibility only.
* @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(MIWatchpointScopeEvent e) {
// When a watchpoint goes out of scope, it is automatically removed from
// the back-end. To keep our internal state synchronized, we have to
// remove it from our breakpoints map.
IBreakpointsTargetDMContext bpContext = DMContexts.getAncestorOfType(e.getDMContext(),
IBreakpointsTargetDMContext.class);
if (bpContext != null) {
Map<String, MIBreakpointDMData> contextBps = getBreakpointMap(bpContext);
if (contextBps != null) {
contextBps.remove(e.getNumber());
}
}
}
/**
* @since 1.1
* @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(ICommandControlShutdownDMEvent e) {
}
///////////////////////////////////////////////////////////////////////////
// IBreakpoints interface
///////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------
// getBreakpoints
//-------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IBreakpoints#getBreakpoints(org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void getBreakpoints(final IBreakpointsTargetDMContext context,
final DataRequestMonitor<IBreakpointDMContext[]> drm) {
// Validate the context
if (context == null) {
drm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null));
drm.done();
return;
}
// Select the breakpoints context map
// If it doesn't exist then no breakpoint was ever inserted for this breakpoint space.
// In that case, return an empty list.
final Map<String, MIBreakpointDMData> breakpointContext = getBreakpointMap(context);
if (breakpointContext == null) {
drm.setData(new IBreakpointDMContext[0]);
drm.done();
return;
}
// Execute the command
fConnection.queueCommand(fCommandFactory.createMIBreakList(context),
new DataRequestMonitor<MIBreakListInfo>(getExecutor(), drm) {
@Override
protected void handleSuccess() {
// Refresh the breakpoints map and format the result
breakpointContext.clear();
MIBreakpoint[] breakpoints = getData().getMIBreakpoints();
IBreakpointDMContext[] result = new IBreakpointDMContext[breakpoints.length];
for (int i = 0; i < breakpoints.length; i++) {
MIBreakpointDMData breakpoint = createMIBreakpointDMData(breakpoints[i]);
String reference = breakpoint.getReference();
result[i] = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context },
reference);
breakpointContext.put(reference, breakpoint);
}
drm.setData(result);
drm.done();
}
});
}
//-------------------------------------------------------------------------
// getBreakpointDMData
//-------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IBreakpoints#getBreakpointDMData(org.eclipse.cdt.dsf.debug.service.IBreakpoints.IDsfBreakpointDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void getBreakpointDMData(IBreakpointDMContext dmc, DataRequestMonitor<IBreakpointDMData> drm) {
// Validate the breakpoint context
if (dmc == null) {
drm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
drm.done();
return;
}
// Validate the breakpoint type
MIBreakpointDMContext breakpoint;
if (dmc instanceof MIBreakpointDMContext) {
breakpoint = (MIBreakpointDMContext) dmc;
} else {
drm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
drm.done();
return;
}
// Validate the target context
IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(breakpoint,
IBreakpointsTargetDMContext.class);
if (context == null) {
drm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null));
drm.done();
return;
}
// Select the breakpoints context map
Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
drm.done();
return;
}
// No need to go to the back-end for this one
MIBreakpointDMData breakpointDMData = contextBreakpoints.get(breakpoint.getReference());
IBreakpointDMData breakpointDMDataCopy = breakpointDMData.copy();
drm.setData(breakpointDMDataCopy);
drm.done();
}
//-------------------------------------------------------------------------
// insertBreakpoint
//-------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IBreakpoints#insertBreakpoint(org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext, java.util.Map, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
*/
@Override
public void insertBreakpoint(IBreakpointsTargetDMContext context, Map<String, Object> attributes,
DataRequestMonitor<IBreakpointDMContext> drm) {
// Validate the context
if (context == null) {
drm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null));
drm.done();
return;
}
// Select the breakpoints context map. If it doesn't exist, create it.
Map<String, MIBreakpointDMData> breakpointContext = getBreakpointMap(context);
if (breakpointContext == null) {
breakpointContext = createNewBreakpointMap(context);
}
// Validate the breakpoint type
String type = (String) attributes.get(BREAKPOINT_TYPE);
if (type == null) {
drm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
drm.done();
return;
}
// And go...
if (type.equals(BREAKPOINT)) {
addBreakpoint(context, attributes, drm);
} else if (type.equals(WATCHPOINT)) {
addWatchpoint(context, attributes, drm);
} else if (type.equals(MIBreakpoints.TRACEPOINT)) {
addTracepoint(context, attributes, drm);
} else if (type.equals(MIBreakpoints.CATCHPOINT)) {
addCatchpoint(context, attributes, drm);
} else if (type.equals(MIBreakpoints.DYNAMICPRINTF)) {
addDynamicPrintf(context, attributes, drm);
} else {
drm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
drm.done();
}
}
/**
* @since 3.0
*/
@Override
public void getExecutionContextBreakpoints(IExecutionDMContext ctx, DataRequestMonitor<IBreakpointDMContext[]> rm) {
IBreakpointDMContext[] bps = fBreakpointHitMap.get(ctx);
if (bps == null && ctx instanceof IContainerDMContext) {
List<IBreakpointDMContext> bpsList = new ArrayList<>(1);
for (Map.Entry<IExecutionDMContext, IBreakpointDMContext[]> entry : fBreakpointHitMap.entrySet()) {
if (DMContexts.isAncestorOf(entry.getKey(), ctx)) {
for (IBreakpointDMContext bp : entry.getValue()) {
bpsList.add(bp);
}
}
}
bps = bpsList.toArray(new IBreakpointDMContext[bpsList.size()]);
}
rm.setData(bps != null ? bps : new IBreakpointDMContext[0]);
rm.done();
}
/**
* @param map
* @param key
* @param defaultValue
* @return
*/
public Object getProperty(Map<String, Object> map, String key, Object defaultValue) {
return (map.containsKey(key) && (map.get(key) != null)) ? map.get(key) : defaultValue;
}
/**
* Creates a gdb location string for a breakpoint/watchpoint/tracepoint
* given its set of properties.
*
* @param attributes
* @return
* @since 3.0
*/
protected String formatLocation(Map<String, Object> attributes) {
// Unlikely default location
String location = (String) getProperty(attributes, ADDRESS, NULL_STRING);
// Get the relevant parameters
String fileName = (String) getProperty(attributes, FILE_NAME, NULL_STRING);
Integer lineNumber = (Integer) getProperty(attributes, LINE_NUMBER, -1);
String function = (String) getProperty(attributes, FUNCTION, NULL_STRING);
// Fix for Bug264721
if (fileName.contains(" ")) { //$NON-NLS-1$
fileName = "\"" + fileName + "\""; //$NON-NLS-1$//$NON-NLS-2$
}
// GDB seems inconsistent about allowing parentheses so we must remove them.
// Bug 336888
int paren = function.indexOf('(');
if (paren != -1) {
function = function.substring(0, paren);
}
if (!fileName.equals(NULL_STRING)) {
// If the function is set it means we want a function breakpoint
// We must check it first because the line number is still set in this case.
if (!function.equals(NULL_STRING)) {
location = fileName + ":" + function; //$NON-NLS-1$
} else {
location = fileName + ":" + lineNumber; //$NON-NLS-1$
}
} else if (!function.equals(NULL_STRING)) {
// function location without source
location = function;
} else if (!location.isEmpty()) {
// address location
if (Character.isDigit(location.charAt(0))) {
// numeric address needs '*' prefix
location = '*' + location;
}
}
return location;
}
/**
* Add a breakpoint of type BREAKPOINT
*
* @param context
* @param breakpoint
* @param finalRm
*
* @since 3.0
*/
protected void addBreakpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
final DataRequestMonitor<IBreakpointDMContext> finalRm) {
// Select the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
// Extract the relevant parameters (providing default values to avoid potential NPEs)
final String location = formatLocation(attributes);
if (location.equals(NULL_STRING)) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
final Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false);
final Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false);
final String condition = (String) getProperty(attributes, CONDITION, NULL_STRING);
final Integer ignoreCount = (Integer) getProperty(attributes, IGNORE_COUNT, 0);
final String threadId = (String) getProperty(attributes, MIBreakpointDMData.THREAD_ID, "0"); //$NON-NLS-1$
final Step insertBreakpointStep = new Step() {
@Override
public void execute(final RequestMonitor rm) {
fConnection
.queueCommand(
fCommandFactory.createMIBreakInsert(context, isTemporary, isHardware, condition,
ignoreCount, location, threadId),
new DataRequestMonitor<MIBreakInsertInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
// With MI, an invalid location won't generate an error
if (getData().getMIBreakpoints().length == 0) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
BREAKPOINT_INSERTION_FAILURE, null));
rm.done();
return;
}
// Create a breakpoint object and store it in the map
final MIBreakpointDMData newBreakpoint = createMIBreakpointDMData(
getData().getMIBreakpoints()[0]);
String reference = newBreakpoint.getNumber();
if (reference.isEmpty()) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
BREAKPOINT_INSERTION_FAILURE, null));
rm.done();
return;
}
contextBreakpoints.put(reference, newBreakpoint);
// Format the return value
MIBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this,
new IDMContext[] { context }, reference);
finalRm.setData(dmc);
// Flag the event
getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties());
// By default the breakpoint is enabled at creation
// If it wasn't supposed to be, then disable it right away
Map<String, Object> delta = new HashMap<>();
delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true));
modifyBreakpoint(dmc, delta, rm, false);
}
@Override
protected void handleError() {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
BREAKPOINT_INSERTION_FAILURE, getStatus().getException()));
rm.done();
}
});
}
};
fRunControl.executeWithTargetAvailable(context, new Step[] { insertBreakpointStep }, finalRm);
}
/**
* Add a tracepoint. Currently not supported in this version, but only in our GDB 7.0 version.
*
* @param context
* @param attributes
* @param drm
*
* @since 3.0
*/
protected void addTracepoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
final DataRequestMonitor<IBreakpointDMContext> drm) {
// Not supported
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
drm.done();
}
/**
* Add a breakpoint of type WATCHPOINT
*
* @param context
* @param watchpoint
* @param drm
* @since 3.0
*/
protected void addWatchpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
final DataRequestMonitor<IBreakpointDMContext> drm) {
// Pick the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
drm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
drm.done();
return;
}
// Extract the relevant parameters (providing default values to avoid potential NPEs)
String expression = (String) getProperty(attributes, EXPRESSION, NULL_STRING);
boolean isRead = (Boolean) getProperty(attributes, READ, false);
boolean isWrite = (Boolean) getProperty(attributes, WRITE, false);
expression = adjustWatchPointExpression(attributes, expression);
// The DataRequestMonitor for the add request
DataRequestMonitor<MIBreakInsertInfo> addWatchpointDRM = new DataRequestMonitor<MIBreakInsertInfo>(
getExecutor(), drm) {
@Override
protected void handleSuccess() {
// With MI, an invalid location won't generate an error
if (getData().getMIBreakpoints().length == 0) {
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
WATCHPOINT_INSERTION_FAILURE, null));
drm.done();
return;
}
// Create a breakpoint object and store it in the map
final MIBreakpointDMData newBreakpoint = createMIBreakpointDMData(getData().getMIBreakpoints()[0]);
String reference = newBreakpoint.getNumber();
if (reference.isEmpty()) {
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
WATCHPOINT_INSERTION_FAILURE, null));
drm.done();
return;
}
contextBreakpoints.put(reference, newBreakpoint);
// Format the return value
IBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context },
reference);
drm.setData(dmc);
// Flag the event
getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties());
// Condition, ignore count and state can not be specified at watchpoint creation time.
// Therefore, we have to update the watchpoint if any of these is present
Map<String, Object> delta = new HashMap<>();
delta.put(CONDITION, getProperty(attributes, CONDITION, NULL_STRING));
delta.put(IGNORE_COUNT, getProperty(attributes, IGNORE_COUNT, 0));
delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true));
modifyBreakpoint(dmc, delta, drm, false);
}
@Override
protected void handleError() {
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
WATCHPOINT_INSERTION_FAILURE, getStatus().getException()));
drm.done();
}
};
// Execute the command
fConnection.queueCommand(fCommandFactory.createMIBreakWatch(context, isRead, isWrite, expression),
addWatchpointDRM);
}
/**
* Adjust the expression to a format suitable for the debugger back end e.g. adding memory space, range,
* etc..
*
* @since 5.3
*/
protected String adjustWatchPointExpression(final Map<String, Object> attributes, String origExpression) {
String adjustedExpression = origExpression;
if (!origExpression.isEmpty() && Character.isDigit(origExpression.charAt(0))) {
// If expression is a single address, we need the '*' prefix.
adjustedExpression = "*" + origExpression; //$NON-NLS-1$
}
return adjustedExpression;
}
/**
* @since 3.0
*/
protected void addCatchpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
final DataRequestMonitor<IBreakpointDMContext> finalRm) {
// Select the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
// Though CDT allows setting a temporary catchpoint, CDT never makes use of it
assert !(Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false);
// GDB has no support for hardware catchpoints
assert !(Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false);
final String event = (String) getProperty(attributes, CATCHPOINT_TYPE, NULL_STRING);
final String[] args = (String[]) getProperty(attributes, CATCHPOINT_ARGS, null);
final Step insertBreakpointStep = new Step() {
@Override
public void execute(final RequestMonitor rm) {
fConnection.queueCommand(
fCommandFactory.createCLICatch(context, event, args == null ? new String[0] : args),
new DataRequestMonitor<CLICatchInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
// Sanity check
MIBreakpoint miBkpt = getData().getMIBreakpoint();
if (miBkpt == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
CATCHPOINT_INSERTION_FAILURE, null));
rm.done();
return;
}
// Create a breakpoint object and store it in the map
final MIBreakpointDMData newBreakpoint = createMIBreakpointDMData(miBkpt);
String reference = newBreakpoint.getNumber();
if (reference.isEmpty()) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
CATCHPOINT_INSERTION_FAILURE, null));
rm.done();
return;
}
contextBreakpoints.put(reference, newBreakpoint);
// Format the return value
MIBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this,
new IDMContext[] { context }, reference);
finalRm.setData(dmc);
// Flag the event
getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties());
// Condition, ignore count and state cannot be specified at creation time.
// Therefore, we have to update the catchpoint if any of these is present
Map<String, Object> delta = new HashMap<>();
delta.put(CONDITION, getProperty(attributes, CONDITION, NULL_STRING));
delta.put(IGNORE_COUNT, getProperty(attributes, IGNORE_COUNT, 0));
delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true));
modifyBreakpoint(dmc, delta, rm, false);
}
@Override
protected void handleError() {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
CATCHPOINT_INSERTION_FAILURE, getStatus().getException()));
rm.done();
}
});
}
};
fRunControl.executeWithTargetAvailable(context, new Step[] { insertBreakpointStep }, finalRm);
}
/**
* Add a DynamicPrintf. Currently not supported in this version, but only in the GDB 7.7 version.
*
* @since 4.4
*/
protected void addDynamicPrintf(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
final DataRequestMonitor<IBreakpointDMContext> drm) {
// Not supported
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
"Dynamic-Printf usage in CDT requires GDB 7.7 or later", null)); //$NON-NLS-1$
drm.done();
}
//-------------------------------------------------------------------------
// removeBreakpoint
//-------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IBreakpoints#removeBreakpoint(org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
*/
@Override
public void removeBreakpoint(final IBreakpointDMContext dmc, final RequestMonitor finalRm) {
// Validate the breakpoint context
if (dmc == null) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
// Validate the breakpoint type
MIBreakpointDMContext breakpointCtx;
if (dmc instanceof MIBreakpointDMContext) {
breakpointCtx = (MIBreakpointDMContext) dmc;
} else {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
finalRm.done();
return;
}
// Validate the target context
final IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc,
IBreakpointsTargetDMContext.class);
if (context == null) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null));
finalRm.done();
return;
}
// Pick the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
finalRm.done();
return;
}
// Validate the breakpoint
final String reference = breakpointCtx.getReference();
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
if (breakpoint == null) {
finalRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
finalRm.done();
return;
}
deleteBreakpointFromTarget(context, reference, new RequestMonitor(ImmediateExecutor.getInstance(), finalRm) {
@Override
protected void handleCompleted() {
if (isSuccess()) {
getSession().dispatchEvent(new BreakpointRemovedEvent(dmc), getProperties());
contextBreakpoints.remove(reference);
}
finalRm.done();
}
});
}
// -------------------------------------------------------------------------
// updateBreakpoint
//-------------------------------------------------------------------------
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.service.IBreakpoints#updateBreakpoint(org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext, java.util.Map, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
*/
@Override
public void updateBreakpoint(IBreakpointDMContext dmc, Map<String, Object> properties, RequestMonitor rm) {
// Validate the breakpoint context
if (dmc == null) {
rm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
rm.done();
return;
}
// Validate the breakpoint type
MIBreakpointDMContext breakpointCtx;
if (dmc instanceof MIBreakpointDMContext) {
breakpointCtx = (MIBreakpointDMContext) dmc;
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null));
rm.done();
return;
}
// Validate the context
IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class);
if (context == null) {
rm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null));
rm.done();
return;
}
// Pick the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
rm.done();
return;
}
// Validate the breakpoint
final String reference = breakpointCtx.getReference();
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
if (breakpoint == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT, null));
rm.done();
return;
}
modifyBreakpoint(dmc, properties, rm, true);
}
/**
* @param dmc
* @param properties
* @param rm
* @param generateUpdateEvent
*
* @since 3.0
*/
protected void modifyBreakpoint(final IBreakpointDMContext dmc, Map<String, Object> attributes,
final RequestMonitor rm, final boolean generateUpdateEvent) {
// Use a working copy of the attributes since we are going to tamper happily with them
Map<String, Object> properties = new HashMap<>(attributes);
// Retrieve the breakpoint parameters
// At this point, we know their are OK so there is no need to re-validate
MIBreakpointDMContext breakpointCtx = (MIBreakpointDMContext) dmc;
IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class);
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
final String reference = breakpointCtx.getReference();
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
// Track the number of change requests
int numberOfChanges = 0;
final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) {
@Override
protected void handleSuccess() {
if (generateUpdateEvent) {
getSession().dispatchEvent(new BreakpointUpdatedEvent(dmc), getProperties());
}
rm.done();
}
};
// Determine if the breakpoint condition changed
String conditionAttribute = CONDITION;
if (properties.containsKey(conditionAttribute)) {
String oldValue = breakpoint.getCondition();
String newValue = (String) properties.get(conditionAttribute);
if (newValue == null) {
newValue = NULL_STRING;
}
if (!oldValue.equals(newValue)) {
changeCondition(context, reference, newValue, countingRm);
numberOfChanges++;
}
properties.remove(conditionAttribute);
}
// Determine if the breakpoint ignore count changed
String ignoreCountAttribute = IGNORE_COUNT;
if (properties.containsKey(ignoreCountAttribute)) {
Integer oldValue = breakpoint.getIgnoreCount();
Integer newValue = (Integer) properties.get(ignoreCountAttribute);
if (newValue == null) {
newValue = 0;
}
if (!oldValue.equals(newValue)) {
changeIgnoreCount(context, reference, newValue, countingRm);
numberOfChanges++;
}
properties.remove(ignoreCountAttribute);
}
// Determine if the breakpoint state changed
String enableAttribute = IS_ENABLED;
if (properties.containsKey(enableAttribute)) {
Boolean oldValue = breakpoint.isEnabled();
Boolean newValue = (Boolean) properties.get(enableAttribute);
if (newValue == null) {
newValue = false;
}
if (!oldValue.equals(newValue)) {
numberOfChanges++;
if (newValue) {
enableBreakpoint(context, reference, countingRm);
} else {
disableBreakpoint(context, reference, countingRm);
}
}
properties.remove(enableAttribute);
}
// Set the number of completions required
countingRm.setDoneCount(numberOfChanges);
}
/**
* Update the breakpoint condition
*
* @param context
* @param dmc
* @param condition
* @param finalRm
*
* @since 5.0
*/
protected void changeCondition(final IBreakpointsTargetDMContext context, final String reference,
final String condition, final RequestMonitor finalRm) {
// Pick the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
final Step changeConditionStep = new Step() {
@Override
public void execute(final RequestMonitor rm) {
// Queue the command
fConnection.queueCommand(fCommandFactory.createMIBreakCondition(context, reference, condition),
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
if (breakpoint == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
UNKNOWN_BREAKPOINT, null));
rm.done();
return;
}
breakpoint.setCondition(condition);
rm.done();
}
// In case of error (new condition could not be installed for whatever reason),
// GDB "offers" different behaviours depending on its version: it can either keep
// the original condition (the right thing to do) or keep the invalid condition.
// Our sole option is to remove the condition in case of error and rely on the
// upper layer to re-install the right condition.
@Override
protected void handleError() {
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
if (breakpoint == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
UNKNOWN_BREAKPOINT, null));
rm.done();
return;
}
// Remove invalid condition from the back-end breakpoint
breakpoint.setCondition(NULL_STRING);
fConnection.queueCommand(
fCommandFactory.createMIBreakCondition(context, reference, NULL_STRING),
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
// The report the initial problem
protected void handleCompleted() {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
REQUEST_FAILED, INVALID_CONDITION, null));
rm.done();
}
});
}
});
}
};
fRunControl.executeWithTargetAvailable(context, new Step[] { changeConditionStep }, finalRm);
}
/**
* Update the breakpoint ignoreCount
*
* @param context
* @param reference
* @param ignoreCount
* @param finalRm
*
* @since 5.0
*/
protected void changeIgnoreCount(final IBreakpointsTargetDMContext context, final String reference,
final int ignoreCount, final RequestMonitor finalRm) {
// Pick the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
final Step changeIgnoreCountStep = new Step() {
@Override
public void execute(final RequestMonitor rm) {
// Queue the command
fConnection.queueCommand(fCommandFactory.createMIBreakAfter(context, reference, ignoreCount),
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
if (breakpoint == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
UNKNOWN_BREAKPOINT, null));
rm.done();
return;
}
breakpoint.setIgnoreCount(ignoreCount);
rm.done();
}
});
}
};
fRunControl.executeWithTargetAvailable(context, new Step[] { changeIgnoreCountStep }, finalRm);
}
/**
* Enable the breakpoint
*
* @param context
* @param reference
* @param finalRm
*
* @since 5.0
*/
protected void enableBreakpoint(final IBreakpointsTargetDMContext context, final String reference,
final RequestMonitor finalRm) {
// Pick the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
final Step enableBreakpointStep = new Step() {
@Override
public void execute(final RequestMonitor rm) {
// Queue the command
fConnection.queueCommand(fCommandFactory.createMIBreakEnable(context, new String[] { reference }),
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
if (breakpoint == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
UNKNOWN_BREAKPOINT, null));
rm.done();
return;
}
breakpoint.setEnabled(true);
rm.done();
}
});
}
};
fRunControl.executeWithTargetAvailable(context, new Step[] { enableBreakpointStep }, finalRm);
}
/**
* Disable the breakpoint
*
* @param context
* @param dmc
* @param finalRm
*
* @since 5.0
*/
protected void disableBreakpoint(final IBreakpointsTargetDMContext context, final String reference,
final RequestMonitor finalRm) {
// Pick the context breakpoints map
final Map<String, MIBreakpointDMData> contextBreakpoints = getBreakpointMap(context);
if (contextBreakpoints == null) {
finalRm.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null));
finalRm.done();
return;
}
final Step disableBreakpointStep = new Step() {
@Override
public void execute(final RequestMonitor rm) {
// Queue the command
fConnection.queueCommand(fCommandFactory.createMIBreakDisable(context, new String[] { reference }),
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
MIBreakpointDMData breakpoint = contextBreakpoints.get(reference);
if (breakpoint == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED,
UNKNOWN_BREAKPOINT, null));
rm.done();
return;
}
breakpoint.setEnabled(false);
rm.done();
}
});
}
};
fRunControl.executeWithTargetAvailable(context, new Step[] { disableBreakpointStep }, finalRm);
}
/**
* This method deletes the target breakpoint with the given reference number.
* @since 5.0
*/
protected void deleteBreakpointFromTarget(final IBreakpointsTargetDMContext context, final String reference,
RequestMonitor finalRm) {
final Step deleteBreakpointStep = new Step() {
@Override
public void execute(final RequestMonitor rm) {
// Queue the command
fConnection.queueCommand(fCommandFactory.createMIBreakDelete(context, new String[] { reference }),
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
}
};
fRunControl.executeWithTargetAvailable(context, new Step[] { deleteBreakpointStep }, finalRm);
}
/**
* @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(IBreakpointHitDMEvent e) {
if (e instanceof IContainerSuspendedDMEvent) {
IExecutionDMContext[] triggeringContexts = ((IContainerSuspendedDMEvent) e).getTriggeringContexts();
if (triggeringContexts != null) {
for (IExecutionDMContext ctx : triggeringContexts) {
fBreakpointHitMap.put(ctx, e.getBreakpoints());
}
} else {
fBreakpointHitMap.put(e.getDMContext(), e.getBreakpoints());
}
} else {
fBreakpointHitMap.put(e.getDMContext(), e.getBreakpoints());
}
}
/**
* @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(IResumedDMEvent e) {
if (e instanceof IContainerResumedDMEvent) {
clearBreakpointHitForContainer((IContainerDMContext) e.getDMContext());
} else {
fBreakpointHitMap.remove(e.getDMContext());
}
}
/**
* Event handler when a thread is destroyed
* @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(IExitedDMEvent e) {
if (e.getDMContext() instanceof IContainerDMContext) {
clearBreakpointHitForContainer((IContainerDMContext) e.getDMContext());
} else {
fBreakpointHitMap.remove(e.getDMContext());
}
}
private void clearBreakpointHitForContainer(IContainerDMContext container) {
for (Iterator<Map.Entry<IExecutionDMContext, IBreakpointDMContext[]>> itr = fBreakpointHitMap.entrySet()
.iterator(); itr.hasNext();) {
if (DMContexts.isAncestorOf(itr.next().getKey(), container)) {
itr.remove();
}
}
fBreakpointHitMap.remove(container);
}
/**
* Returns a breakpoint target context for given breakpoint number.
* @since 5.0
*/
protected IBreakpointsTargetDMContext getBreakpointTargetContext(String reference) {
for (IBreakpointsTargetDMContext context : fBreakpoints.keySet()) {
Map<String, MIBreakpointDMData> map = fBreakpoints.get(context);
if (map != null && map.keySet().contains(reference)) {
return context;
}
}
return null;
}
/**
* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=232415
* Returns the simple filename if running on Windows and [originalPath] is not an
* absolute UNIX one. Otherwise, [originalPath] is returned
* @since 4.2
*/
@Override
public String adjustDebuggerPath(String originalPath) {
String result = originalPath;
// Make it MinGW-specific
if (Platform.getOS().startsWith("win")) { //$NON-NLS-1$
if (!originalPath.startsWith("/")) { //$NON-NLS-1$
originalPath = originalPath.replace('\\', '/');
result = originalPath.substring(originalPath.lastIndexOf('/') + 1);
}
}
return result;
}
}