blob: a41918a862968d7aa3aec1812a52537840d16e4e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2011 Nokia 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:
* Nokia - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.edc.internal.services.dsf;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.IllegalFormatException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager;
import org.eclipse.cdt.debug.core.breakpointactions.IBreakpointAction;
import org.eclipse.cdt.debug.core.model.ICBreakpoint;
import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
import org.eclipse.cdt.debug.core.model.ICWatchpoint;
import org.eclipse.cdt.debug.core.model.ICWatchpoint2;
import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
import org.eclipse.cdt.debug.edc.internal.EDCTrace;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleDMC;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleLoadedEvent;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleUnloadedEvent;
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
import org.eclipse.cdt.debug.edc.services.AbstractEDCService;
import org.eclipse.cdt.debug.edc.services.DMContext;
import org.eclipse.cdt.debug.edc.services.IDSFServiceUsingTCF;
import org.eclipse.cdt.debug.edc.services.IEDCDMContext;
import org.eclipse.cdt.debug.edc.services.IEDCExpression;
import org.eclipse.cdt.debug.edc.services.ITargetEnvironment;
import org.eclipse.cdt.debug.edc.services.Stack;
import org.eclipse.cdt.debug.edc.tcf.extension.ProtocolConstants.IModuleProperty;
import org.eclipse.cdt.debug.internal.core.breakpoints.BreakpointProblems;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
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.concurrent.RequestMonitorWithProgress;
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.BreakpointsMediator2;
import org.eclipse.cdt.dsf.debug.service.IBreakpointAttributeTranslator;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
import org.eclipse.cdt.dsf.debug.service.IModules.ModuleLoadedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IModules.ModuleUnloadedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.Addr32;
import org.eclipse.cdt.utils.Addr64;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.model.MemoryByte;
import org.eclipse.tm.tcf.protocol.IService;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IBreakpoints.DoneCommand;
public class Breakpoints extends AbstractEDCService implements IBreakpoints, IDSFServiceUsingTCF {
/**
* 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
* {@link IBreakpointAttributeTranslator} 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.debug.edc.breakpoint"; //$NON-NLS-1$
// Our own attribute keys.
//
/**
* Breakpoint type: value is string.
*/
public static final String BREAKPOINT_TYPE = PREFIX + ".type"; //$NON-NLS-1$
// type values:
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$
/**
* breakponint sub-type: value is string.
*/
public static final String BREAKPOINT_SUBTYPE = PREFIX + ".subtype"; //$NON-NLS-1$
// sub-type values:
public static final String LINE_BREAKPOINT = "line_bp"; //$NON-NLS-1$
public static final String FUNCTION_BREAKPOINT = "function_bp"; //$NON-NLS-1$
public static final String ADDRESS_BREAKPOINT = "address_bp"; //$NON-NLS-1$
/**
* breakpoint runtime address: value is hex string with no preceding "0x".
*/
public static final String RUNTIME_ADDRESS = PREFIX + ".runtime_addr";
/**
* TCF properties using keys from {@link org.eclipse.tm.tcf.services.IBreakpoints}
*/
public static final String TCF_PROPERTIES = PREFIX + ".tcf_properties"; //$NON-NLS-1$
private static final String TCF_BP_ACCESSMODE = org.eclipse.tm.tcf.services.IBreakpoints.PROP_ACCESSMODE;
// private static final int TCF_BP_ACCESSMODE_CHANGE = org.eclipse.tm.tcf.services.IBreakpoints.ACCESSMODE_CHANGE;
private static final int TCF_BP_ACCESSMODE_EXECUTE = org.eclipse.tm.tcf.services.IBreakpoints.ACCESSMODE_EXECUTE;
private static final int TCF_BP_ACCESSMODE_READ = org.eclipse.tm.tcf.services.IBreakpoints.ACCESSMODE_READ;
private static final int TCF_BP_ACCESSMODE_WRITE = org.eclipse.tm.tcf.services.IBreakpoints.ACCESSMODE_WRITE;
private static final String TCF_BP_CONDITION = org.eclipse.tm.tcf.services.IBreakpoints.PROP_CONDITION;
private static final String TCF_BP_CONTEXTIDS = org.eclipse.tm.tcf.services.IBreakpoints.PROP_CONTEXTIDS;
private static final String TCF_BP_ENABLED = org.eclipse.tm.tcf.services.IBreakpoints.PROP_ENABLED;
private static final String TCF_BP_FILE = org.eclipse.tm.tcf.services.IBreakpoints.PROP_FILE;
private static final String TCF_BP_ID = org.eclipse.tm.tcf.services.IBreakpoints.PROP_ID;
private static final String TCF_BP_IGNORECOUNT = org.eclipse.tm.tcf.services.IBreakpoints.PROP_IGNORECOUNT;
private static final String TCF_BP_LINE = org.eclipse.tm.tcf.services.IBreakpoints.PROP_LINE;
private static final String TCF_BP_LOCATION = org.eclipse.tm.tcf.services.IBreakpoints.PROP_LOCATION;
private static final String TCF_BP_SIZE = org.eclipse.tm.tcf.services.IBreakpoints.PROP_SIZE;
private static final String TCF_BP_TYPE = org.eclipse.tm.tcf.services.IBreakpoints.PROP_TYPE;
private static final String TCF_BP_TYPE_AUTO = org.eclipse.tm.tcf.services.IBreakpoints.TYPE_AUTO;
// Error messages
static final String NULL_STRING = ""; //$NON-NLS-1$
static final String UNKNOWN_EXECUTION_CONTEXT = "Unknown execution context"; //$NON-NLS-1$
static final String UNKNOWN_BREAKPOINT_CONTEXT = "Unknown breakpoint context"; //$NON-NLS-1$
static final String UNKNOWN_BREAKPOINT_TYPE = "Unknown breakpoint type"; //$NON-NLS-1$
static final String UNKNOWN_BREAKPOINT = "Unknown breakpoint"; //$NON-NLS-1$
static final String BREAKPOINT_INSERTION_FAILURE = "Breakpoint insertion failure"; //$NON-NLS-1$
static final String WATCHPOINT_INSERTION_FAILURE = "Watchpoint insertion failure"; //$NON-NLS-1$
static final String INVALID_CONDITION = "Invalid condition"; //$NON-NLS-1$
// User breakpoints (those from the IDE) currently installed.
private final Map<IBreakpointDMContext, BreakpointDMData> userBreakpoints = new HashMap<IBreakpointDMContext, BreakpointDMData>();
/**
* Internal temporary breakpoints set by debugger for stepping.
*/
private final List<BreakpointDMData> tempBreakpoints = new ArrayList<BreakpointDMData>();
private org.eclipse.tm.tcf.services.IBreakpoints tcfBreakpointService;
// Module in which startup breakpoint is installed for the debug session.
private Map<ILaunchConfiguration, ModuleDMC> startupBreakpointModule = new HashMap<ILaunchConfiguration, ModuleDMC>();
private ISourceLocator sourceLocator;
/**
* Breakpoint problem markers added by EDC. Note these markers have life-span
* of a debug session, namely they are removed at end of a debug session or
* removed when corresponding breakpoint is removed by user.
*
* Currently the markers are only used for breakpoint conditions, though it should
* be easy to extend the scope.....06/07/2011.
*/
private Map<IBreakpointDMContext, IMarker> fBreakpointMarkers = new HashMap<IBreakpointDMContext, IMarker>();
static private long nextBreakpointID = 1;
// /////////////////////////////////////////////////////////////////////////
// Breakpoint Events
// /////////////////////////////////////////////////////////////////////////
public class BreakpointsChangedEvent extends AbstractDMEvent<IBreakpointsTargetDMContext> implements
IBreakpointsChangedEvent {
private IBreakpointDMContext[] eventBreakpoints;
public BreakpointsChangedEvent(IBreakpointDMContext bp) {
super(DMContexts.getAncestorOfType(bp, IBreakpointsTargetDMContext.class));
eventBreakpoints = new IBreakpointDMContext[] { bp };
}
public IBreakpointDMContext[] getBreakpoints() {
return eventBreakpoints;
}
}
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
// /////////////////////////////////////////////////////////////////////////
@Immutable
public static final class BreakpointDMContext extends DMContext implements IBreakpointDMContext {
public BreakpointDMContext(String sessionID, IDMContext[] parents, long id) {
super(sessionID, parents, Long.toString(id));
}
@Override
public String toString() {
return "BreakpointDMContext [id=" + getID() + "]";
}
}
public class BreakpointDMData implements IBreakpointDMData {
private final long id; // internal ID.
private final IBreakpointDMContext context;
private final IAddress[] addresses;
private final byte[] originalInstruction;
private Map<String, Object> properties;
private int hitCount;
public BreakpointDMData(long id, IBreakpointDMContext context, IAddress[] addresses,
Map<String, Object> properties) {
super();
this.id = id;
this.context = context;
this.addresses = addresses;
this.originalInstruction = null;
this.properties = new HashMap<String, Object>(properties); // make a copy
}
public BreakpointDMData(long id, IBreakpointDMContext context, IAddress[] addresses,
byte[] fOriginalInstruction, Map<String, Object> properties) {
super();
this.id = id;
this.context = context;
this.addresses = addresses;
this.originalInstruction = fOriginalInstruction;
this.properties = new HashMap<String, Object>(properties);
}
public IAddress[] getAddresses() {
return addresses;
}
public String getBreakpointType() {
return (String) properties.get(BREAKPOINT_TYPE);
}
public String getCondition() {
return (String) properties.get(ICBreakpoint.CONDITION);
}
public String getExpression() {
return (String) properties.get(ICWatchpoint.EXPRESSION);
}
public String getFileName() {
return (String) properties.get(ICBreakpoint.SOURCE_HANDLE);
}
public String getFunctionName() {
return (String) properties.get(ICLineBreakpoint.FUNCTION);
}
public int getIgnoreCount() {
Integer ic = (Integer) properties.get(ICBreakpoint.IGNORE_COUNT);
if (ic == null)
return 0;
else
return ic.intValue();
}
public int getLineNumber() {
return (Integer) properties.get(IMarker.LINE_NUMBER);
}
public boolean isEnabled() {
return (Boolean) properties.get(IBreakpoint.ENABLED);
}
public long getID() {
return id;
}
public byte[] getOriginalInstruction() {
return originalInstruction;
}
/**
* @return reference to properties map of the bp.
*/
public Map<String, Object> getProperties() {
return properties;
}
public IBreakpointDMContext getContext() {
return context;
}
@SuppressWarnings("unchecked")
public Map<String, Object> getTCFProperties() {
return (Map<String, Object>)properties.get(TCF_PROPERTIES);
}
public void setProperties(Map<String, Object> props) {
properties = new HashMap<String, Object>(props);
}
public void setTCFProperties(Map<String, Object> tcfprops) {
// insert a copy of the properties
properties.put(TCF_PROPERTIES, new HashMap<String, Object>(tcfprops));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + (int) (id ^ (id >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BreakpointDMData other = (BreakpointDMData) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (id != other.id)
return false;
return true;
}
private Breakpoints getOuterType() {
return Breakpoints.this;
}
@Override
public String toString() {
String s = getFileName();
if (s == null) // address breakpoint
s = getAddresses()[0].toHexAddressString();
else {
if (getFunctionName() != null)
s += ": " + getFunctionName();
else
s += ":line " + getLineNumber();
}
return "Breakpoint@" + s;
}
public void incrementHitCount() {
hitCount++;
}
public int getHitCount() {
return hitCount;
}
public boolean hasActions() {
return properties.containsKey(BreakpointActionManager.BREAKPOINT_ACTION_ATTRIBUTE);
}
private void doExecuteActions(final RunControl.ExecutionDMC threadDMC, final RequestMonitorWithProgress rm) {
assert getExecutor().isInExecutorThread();
BreakpointsMediator2 bpm2 = getService(BreakpointsMediator2.class);
final IBreakpoint ibp
= (bpm2 != null) ? bpm2.getPlatformBreakpoint(null, getContext()) : null;
String actionProp = (String)properties.get(BreakpointActionManager.BREAKPOINT_ACTION_ATTRIBUTE);
String[] actionNames = actionProp.split(",");
for (int i = 0; i < actionNames.length; ++i) {
final IBreakpointAction action
= CDebugCorePlugin.getDefault().getBreakpointActionManager().findBreakpointAction(actionNames[i]);
if (action != null) {
Runnable runnable = new Runnable() {
public void run() {
action.execute(ibp, threadDMC, rm.getProgressMonitor());
}
};
asyncExec(runnable, rm);
}
}
}
public void executeActions(final RunControl.ExecutionDMC threadDMC, final RequestMonitorWithProgress rm) {
if (!hasActions())
return;
if (getExecutor().isInExecutorThread()) {
doExecuteActions(threadDMC, rm);
} else {
getExecutor().execute(new Runnable() {
public void run() {
doExecuteActions(threadDMC, rm);
}
});
}
}
}
public Breakpoints(DsfSession session) {
super(session, new String[] { IBreakpoints.class.getName(), Breakpoints.class.getName() });
}
@Override
public void initialize(final RequestMonitor rm) {
super.initialize(new RequestMonitor(getExecutor(), rm) {
@Override
protected void handleSuccess() {
// Register as event listener.
getSession().addServiceEventListener(Breakpoints.this, null);
rm.done();
}
});
}
public void getBreakpointDMData(IBreakpointDMContext dmc, DataRequestMonitor<IBreakpointDMData> drm) {
if (!userBreakpoints.containsKey(dmc)) {
drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, UNKNOWN_BREAKPOINT));
} else
drm.setData(userBreakpoints.get(dmc));
drm.done();
}
public void getBreakpoints(IBreakpointsTargetDMContext context, DataRequestMonitor<IBreakpointDMContext[]> drm) {
Set<IBreakpointDMContext> breakpointIDs = userBreakpoints.keySet();
drm.setData(breakpointIDs.toArray(new IBreakpointDMContext[breakpointIDs.size()]));
drm.done();
}
/**
* Find breakpoint, either user-set or debugger internal temporary one, at
* the given address.
*
* @param addr
* - absolute runtime address.
* @return null if not found.
*/
public BreakpointDMData findBreakpoint(IAddress addr) {
BreakpointDMData bp = findUserBreakpoint(addr);
if (bp == null)
bp = findTempBreakpoint(addr);
return bp;
}
/**
* Find user breakpoint at the given address.
*
* @param addr
* - absolute runtime address.
* @return null if not found.
*/
public BreakpointDMData findUserBreakpoint(IAddress addr) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "Find user breakpoint at " + addr.toHexAddressString()); }
for (BreakpointDMData bp : userBreakpoints.values())
if (bp.getAddresses()[0].equals(addr)) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(bp.toString())); }
return bp;
}
if (EDCTrace.BREAKPOINTS_TRACE_ON) {EDCTrace.getTrace().traceExit(null, "not found.");}
return null;
}
/**
* Find a temporary breakpoint at the given address.
*
* @param addr
* - absolute runtime address.
* @return null if not found.
*/
public BreakpointDMData findTempBreakpoint(IAddress addr) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "Find temp breakpoint at " + addr.toHexAddressString()); }
for (BreakpointDMData bp : tempBreakpoints) {
if (bp.getAddresses()[0].equals(addr)) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(bp.toString())); }
return bp;
}
}
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, "not found."); }
return null;
}
/**
* Remove software breakpoints inserted in memory by debugger from the given
* memory buffer starting from given address.
*
* @param startAddr
* start address of the memory data.
* @param memBuffer
* a buffer containing data from memory. Its content will be
* changed by this method if a breakpoint falls in the address
* range.
*/
public void removeBreakpointFromMemoryBuffer(IAddress startAddr, MemoryByte[] memBuffer) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "remove bp in memory area:" + startAddr.toHexAddressString() + "," + memBuffer.length); }
// If the breakpoint is actually set by TCF agent, we have to assume
// that the TCF agent would do this breakpoint removing for us as
// we have no idea how the agent set the breakpoint (e.g. is it software
// breakpoint ? if yes, what breakpoint instruction is used ?)
//
if (usesTCFBreakpointService())
return;
for (BreakpointDMData edcBp : userBreakpoints.values()) {
// TODO: bail out if the bp is not software breakpoint.
IAddress bpAddr = edcBp.getAddresses()[0];
int bpOffset = (int) startAddr.distanceTo(bpAddr).longValue();
if (bpOffset >= 0 && bpOffset < memBuffer.length) {
// the breakpoint falls in the buffer. Restore the original
// instruction.
byte[] orgInst = edcBp.getOriginalInstruction();
for (int i = 0; i < orgInst.length && i + bpOffset < memBuffer.length; i++) {
memBuffer[bpOffset + i].setValue(orgInst[i]);
}
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "breakpoint removed at offset " + bpOffset); }
}
}
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
public void insertBreakpoint(IBreakpointsTargetDMContext context, Map<String, Object> attributes,
DataRequestMonitor<IBreakpointDMContext> drm) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { attributes })); }
// Validate the context
if (context == null) {
drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT,
null));
drm.done();
return;
}
// Validate the breakpoint type
String type = (String) attributes.get(BREAKPOINT_TYPE);
if (type == null) {
drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.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 {
drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE,
null));
drm.done();
}
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
/**
* Set one target breakpoint.
*
* @param context
* @param attributes
* attributes for the target breakpoint. For EDC, it must contain
* the RUNTIME_ADDRESS attribute.
* @param drm
*/
private void addBreakpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
final DataRequestMonitor<IBreakpointDMContext> drm) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { attributes })); }
IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
String bpAddr = (String)attributes.get(RUNTIME_ADDRESS);
assert exe_dmc != null : "ExecutionDMContext is unknown in addBreakpoint().";
assert bpAddr != null;
createBreakpoint(exe_dmc, new Addr64(bpAddr, 16), attributes, new DataRequestMonitor<BreakpointDMData>(
getExecutor(), drm) {
@Override
protected void handleSuccess() {
final BreakpointDMData bpd = getData();
enableBreakpoint(bpd, new RequestMonitor(getExecutor(), drm) {
@Override
protected void handleSuccess() {
IBreakpointDMContext bp_dmc = bpd.getContext();
drm.setData(bp_dmc);
// Remember this in our global list.
userBreakpoints.put(bp_dmc, bpd);
drm.done();
}
});
}
});
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
/**
* Set one target watchpoint.
*
* @param context
* @param attributes
* attributes for the target breakpoint. For EDC, it must contain
* the RUNTIME_ADDRESS attribute.
* @param drm
*/
private void addWatchpoint(final IBreakpointsTargetDMContext context, final Map<String, Object> attributes,
final DataRequestMonitor<IBreakpointDMContext> drm) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { attributes })); }
IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
String bpAddr = (String)attributes.get(RUNTIME_ADDRESS);
assert exe_dmc != null : "DMContext is unknown in addWatchpoint().";
assert bpAddr != null;
createWatchpoint(exe_dmc, new Addr64(bpAddr, 16), attributes, new DataRequestMonitor<BreakpointDMData>(
getExecutor(), drm) {
@Override
protected void handleSuccess() {
final BreakpointDMData bpd = getData();
enableBreakpoint(bpd, new RequestMonitor(getExecutor(), drm) {
@Override
protected void handleSuccess() {
IBreakpointDMContext bp_dmc = bpd.getContext();
drm.setData(bp_dmc);
// Remember this in our global list.
userBreakpoints.put(bp_dmc, bpd);
drm.done();
}
});
}
});
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
public ISourceLocator getSourceLocator() {
return sourceLocator;
}
public void setSourceLocator(ISourceLocator sourceLocator) {
this.sourceLocator = sourceLocator;
}
/**
* Set temporary breakpoint at given address. This is for cases such as
* stepping and initial startup breakpoint (aka entry breakpoint).<br>
* If a user or temporary breakpoint already exists at the address, no
* temporary breakpoint will be set.
*
* @param context
* @param address
* @param rm
*/
public void setTempBreakpoint(final IExecutionDMContext context, final IAddress address, final RequestMonitor rm) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "set temp breakpoint at " + address.toHexAddressString()); }
// If a breakpoint (user-set or temp) exists at the address, we are
// done.
if (findBreakpoint(address) != null) {
rm.done();
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, "A breakpoint exists at " + address.toHexAddressString()); }
return;
}
createBreakpoint(context, address, new HashMap<String, Object>(), new DataRequestMonitor<BreakpointDMData>(
getExecutor(), rm) {
@Override
protected void handleSuccess() {
final BreakpointDMData bp_data = getData();
enableBreakpoint(bp_data, new RequestMonitor(getExecutor(), rm) {
@Override
protected void handleSuccess() {
// Remember this in our list.
tempBreakpoints.add(bp_data);
rm.done();
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg("A temp breakpoint successfully set at " + address.toHexAddressString())); }
}
});
}
});
}
/**
* Remove all temporary breakpoints set so far.
*
* @param rm
*/
public void removeAllTempBreakpoints(final RequestMonitor rm) {
int numTempBps = tempBreakpoints.size();
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, "remove " + numTempBps + " temp breakpoint" + ((numTempBps == 1)?"":"s") + "."); }
if (numTempBps == 0) {
rm.done();
return;
}
CountingRequestMonitor crm = new CountingRequestMonitor(getExecutor(), rm) {
@Override
protected void handleCompleted() {
if (getStatus().isOK()) {
tempBreakpoints.clear();
}
super.handleCompleted();
}
};
crm.setDoneCount(tempBreakpoints.size());
for (BreakpointDMData bp : tempBreakpoints)
disableBreakpoint(bp, crm);
}
private void createBreakpoint(final IExecutionDMContext exeDMC,
final IAddress address, final Map<String, Object> allProps,
final DataRequestMonitor<BreakpointDMData> drm) {
asyncExec(new Runnable() {
public void run() {
final long id = getNewBreakpointID();
final IBreakpointDMContext bp_dmc
= new BreakpointDMContext(getSession().getId(),
new IDMContext[] { exeDMC },
id);
final IAddress[] bp_addrs = new IAddress[] { address };
if (usesTCFBreakpointService()) {
final Map<String, Object> tcfProperties = new HashMap<String, Object>();
tcfProperties.put(TCF_BP_ACCESSMODE, TCF_BP_ACCESSMODE_EXECUTE);
tcfProperties.put(TCF_BP_ID, Long.toString(id));
tcfProperties.put(TCF_BP_ENABLED, true);
tcfProperties.put(TCF_BP_TYPE, TCF_BP_TYPE_AUTO);
tcfProperties.put(TCF_BP_LOCATION, address.toString());
tcfProperties.put(TCF_BP_CONTEXTIDS, getTcfContextIDs(exeDMC));
ITargetEnvironment te = getTargetEnvironmentService();
te.updateBreakpointProperties(exeDMC, address, tcfProperties);
transferOptionalTcfProperties(allProps, tcfProperties);
// save the separated TCF properties as a property
// set amongst the regular properties; makes them
// easy to pass as a set when calling the agent's add()
allProps.put(TCF_PROPERTIES, tcfProperties);
drm.setData(new BreakpointDMData(id, bp_dmc, bp_addrs, allProps));
drm.done();
} else { // generic software breakpoint
final byte[] bpInstruction = getTargetEnvironmentService().getBreakpointInstruction(exeDMC, address);
final int inst_size = bpInstruction.length;
Memory memoryService = getService(Memory.class);
IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(exeDMC, IMemoryDMContext.class);
memoryService.getMemory(mem_dmc, address, 0, 1, inst_size, new DataRequestMonitor<MemoryByte[]>(
getExecutor(), drm) {
@Override
protected void handleSuccess() {
MemoryByte[] org_inst = getData();
final byte[] org_inst_bytes = new byte[org_inst.length];
for (int i = 0; i < org_inst.length; i++) {
// make sure each byte is okay
if (!org_inst[i].isReadable()) {
drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
("Cannot read memory at 0x" + address.add(i).getValue().toString(16)),
null));
drm.done();
return;
}
org_inst_bytes[i] = org_inst[i].getValue();
}
drm.setData(new BreakpointDMData(id, bp_dmc, bp_addrs, org_inst_bytes, allProps));
drm.done();
}
});
}
}
}, drm);
}
private void createWatchpoint(final IDMContext dmc, final IAddress address,
final Map<String, Object> allProps,
final DataRequestMonitor<BreakpointDMData> drm) {
asyncExec(new Runnable() {
public void run() {
final long id = getNewBreakpointID();
final IBreakpointDMContext bp_dmc
= new BreakpointDMContext(getSession().getId(),
new IDMContext[] { dmc },
id);
final IAddress[] bp_addrs = new IAddress[] { address };
if (hasTCFWatchpointSupport()) {
final Map<String, Object> tcfProperties = new HashMap<String, Object>();
tcfProperties.put(TCF_BP_ID, Long.toString(id));
tcfProperties.put(TCF_BP_ENABLED, true);
tcfProperties.put(TCF_BP_TYPE, TCF_BP_TYPE_AUTO);
tcfProperties.put(TCF_BP_LOCATION, address.toString());
Boolean wpRead = (Boolean)allProps.get(ICWatchpoint.READ);
Boolean wpWrite = (Boolean)allProps.get(ICWatchpoint.WRITE);
int accessMode
= ((wpRead != null && wpRead) ? TCF_BP_ACCESSMODE_READ : 0)
| ((wpWrite != null && wpWrite) ? TCF_BP_ACCESSMODE_WRITE : 0);
tcfProperties.put(TCF_BP_ACCESSMODE, accessMode);
Number wpSize = (Number)allProps.get(ICWatchpoint2.RANGE);
if (wpSize != null)
tcfProperties.put(TCF_BP_SIZE, wpSize);
tcfProperties.put(TCF_BP_CONTEXTIDS, getTcfContextIDs(dmc));
ITargetEnvironment te = getTargetEnvironmentService();
te.updateBreakpointProperties(dmc, address, tcfProperties);
transferOptionalTcfProperties(allProps, tcfProperties);
allProps.put(TCF_PROPERTIES, tcfProperties);
drm.setData(new BreakpointDMData(id, bp_dmc, bp_addrs, allProps));
} else { // generic software watchpoint? i don't think so, tim!
drm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
"Watchpoints not supported for this system", null));
}
drm.done();
}
}, drm);
}
/**
* Pass "contexts" for which the BP/WP is supposed to work.
* <br>
* Commonly utility used when creating breakpoint or watchpoint
*
* @param dmc
* @return String[] array representing contexts<br>
* NOTE: EDC extension to TCF:
* TCF only define "IBreakpoints.PROP_CONTEXTIDS" as an array of IDs.
* In EDC, it's required the first element in the array be
* IBreakpointsTargetDMContext which is usually (but not always) a
* process. This makes EDC backward compatible with some existing TCF agents.
*
*/
private String[] getTcfContextIDs(final IDMContext dmc) {
// Pass "contexts" for which the BP is supposed to work.
// NOTE: EDC extension to TCF:
IBreakpointsTargetDMContext bpTargetDMC
= DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class);
// pass "dmc" as a context if it's different from bpTargetDMC
if (! dmc.equals(bpTargetDMC))
return new String[] {((IEDCDMContext)bpTargetDMC).getID(),
((IEDCDMContext)dmc).getID()};
return new String[] {((IEDCDMContext)bpTargetDMC).getID()};
}
/**
* Looks for properties recognized by TCF and puts them in
* the propertie list that will passed to the agent.
* <br>
* Commonly utility used when creating breakpoint or watchpoint
* @param bpProps
* @param tcfProperties
*/
private void transferOptionalTcfProperties(
final Map<String, Object> bpProps,
final Map<String, Object> tcfProperties) {
// the following are optional, and may not apply to all agents
Object sourceHandle = bpProps.get(ICBreakpoint.SOURCE_HANDLE);
if (sourceHandle instanceof String)
tcfProperties.put(TCF_BP_FILE, sourceHandle);
Object lineNumber = bpProps.get(ICBreakpoint.SOURCE_HANDLE);
if (lineNumber instanceof Number)
tcfProperties.put(TCF_BP_LINE, lineNumber);
Object condition = bpProps.get(ICBreakpoint.CONDITION);
if (condition instanceof String)
tcfProperties.put(TCF_BP_CONDITION, condition);
Object ignoreCount = bpProps.get(ICBreakpoint.IGNORE_COUNT);
if (ignoreCount instanceof Number)
tcfProperties.put(TCF_BP_IGNORECOUNT, ignoreCount);
// ok, so the following does not strictly conform to the API.
// however, it helps in logging & debugging, will aid debugging
// watchpoints which have an expression but not a file or
// line-number, and, in the end, will make my friend ed happy.
Object bpMessage = bpProps.get(IMarker.MESSAGE);
if (bpMessage instanceof String)
tcfProperties.put(IMarker.MESSAGE, bpMessage);
}
/**
* Install the breakpoint in the target process.
*
* @param bp
* @param rm
*/
public void enableBreakpoint(final BreakpointDMData bp, final RequestMonitor rm) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(bp)); }
if (usesTCFBreakpointService()) {
Protocol.invokeLater(new Runnable() {
public void run() {
tcfBreakpointService.add(bp.getTCFProperties(), new DoneCommand() {
public void doneCommand(IToken token, Exception error) {
if (error != null) {
// Make sure "done()" is called for the rm.
rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, REQUEST_FAILED,
"TCF agent fails to install " + bp + " because:\n"
+ error.getLocalizedMessage(), error));
rm.done();
} else {
getSession().dispatchEvent(new BreakpointAddedEvent(bp.getContext()),
new Hashtable<String, Object>(bp.getProperties()));
rm.done();
}
}
});
}
});
} else {
IAddress bp_addr = bp.getAddresses()[0];
IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(bp.getContext(), IExecutionDMContext.class);
byte[] bpInstruction = getTargetEnvironmentService().getBreakpointInstruction(exe_dmc, bp_addr);
Memory memoryService = getService(Memory.class);
IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(bp.getContext(), IMemoryDMContext.class);
memoryService.setMemory(mem_dmc, bp_addr, 0, 1, bpInstruction.length, bpInstruction, rm);
getSession().dispatchEvent(new BreakpointAddedEvent(bp.getContext()),
new Hashtable<String, Object>(bp.getProperties()));
}
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
private synchronized long getNewBreakpointID() {
return nextBreakpointID++;
}
public void removeBreakpoint(final IBreakpointDMContext dmc, RequestMonitor rm) {
// Remove user breakpoint in the target.
// This is called when user remove a breakpoint or when debug session ends.
//
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { dmc })); }
if (!(dmc instanceof BreakpointDMContext)) {
// not our breakpoint, should not happen
rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, "Unrecognized breakpoint context."));
rm.done();
return;
}
if (!userBreakpoints.containsKey(dmc)) {
rm.setStatus(new Status(IStatus.ERROR, EDCDebugger.PLUGIN_ID, UNKNOWN_BREAKPOINT));
rm.done();
return;
}
disableBreakpoint(userBreakpoints.get(dmc), new RequestMonitor(getExecutor(), rm) {
@Override
protected void handleCompleted() {
// Regardless of success or failure of removing the bp on target, we'll do following.
//
// If user removes a breakpoint in UI, the platform won't keep the BP in UI just because
// of failure in removing the bp on target. However, any error passed by the "rm" will
// be displayed in Error Log view.
// Remove it from our record.
userBreakpoints.remove(dmc);
// Remove problem marker if any.
// Note this may be called when the debug session is shut down.
removeBreakpointProblemMarker(dmc);
super.handleCompleted();
}
});
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
/**
* Remove the breakpoint from the target process.
*
* @param bp
* @param rm
*/
public void disableBreakpoint(final BreakpointDMData bp, final RequestMonitor rm) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { bp })); }
if (!usesTCFBreakpointService()) {
final Memory memoryService = getService(Memory.class);
IMemoryDMContext mem_dmc = DMContexts.getAncestorOfType(bp.getContext(), IMemoryDMContext.class);
byte[] orgInst = bp.getOriginalInstruction();
memoryService.setMemory(mem_dmc, bp.getAddresses()[0], 0, 1, orgInst.length, orgInst, rm);
} else {
Protocol.invokeLater(new Runnable() {
public void run() {
Map<String, Object> properties = bp.getTCFProperties();
String id = (String) properties.get(org.eclipse.tm.tcf.services.IBreakpoints.PROP_ID);
tcfBreakpointService.remove(new String[] { id }, new DoneCommand() {
public void doneCommand(IToken token, Exception error) {
rm.done();
}
});
}
});
}
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
public void updateBreakpoint(IBreakpointDMContext dmc, Map<String, Object> delta, RequestMonitor rm) {
/*
* For EDC, we don't need to do any update on non-significant attribute
* change, e.g. change of Install_count, ignore_count. For significant
* change, the breakpoint will just be re-installed.
* See canUpdateAttributes().
*/
BreakpointDMData bp = userBreakpoints.get(dmc);
if (bp == null)
assert false : "Fail to find BreakpointDMData linked with the IBreakpointDMContext:" + dmc;
else {
Map<String, Object> existingProps = bp.getProperties();
for (String key : delta.keySet())
existingProps.put(key, delta.get(key));
}
rm.done();
}
public boolean usesTCFBreakpointService() {
return tcfBreakpointService != null;
}
private boolean hasTCFWatchpointSupport() {
return usesTCFBreakpointService(); // TODO && tcfBreakpointService.supportsWatchpoints
}
public void tcfServiceReady(IService service) {
tcfBreakpointService = (org.eclipse.tm.tcf.services.IBreakpoints) service;
}
@DsfServiceEventHandler
public void eventHandler_installBreakpointsForModule(ModuleLoadedDMEvent e) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { e })); }
// A new module (including main exe) is loaded. Install breakpoints for
// it.
ModuleLoadedEvent event = (ModuleLoadedEvent) e;
final IExecutionDMContext executionDMC = event.getExecutionDMC();
final ModuleDMC module = (ModuleDMC) e.getLoadedModuleContext();
BreakpointsMediator2 bm = getService(BreakpointsMediator2.class);
if (bm == null) {
EDCDebugger.getMessageLogger().logError("Fail to get BreakpointsMediator service to install breakpoints for loaded module "+module, null);
assert false;
return;
}
final boolean requireResume = requireResume(module);
IBreakpointsTargetDMContext bt_dmc = DMContexts.getAncestorOfType(module, IBreakpointsTargetDMContext.class);
bm.startTrackingBreakpoints(bt_dmc, new RequestMonitor(getExecutor(), null) {
@Override
protected void handleCompleted() {
if (!isSuccess()) {
// do we want to display a dialog for user ?
// No, as it's expected not all breakpoints can be resolved
// in the module.
// Form readable message and log it.
IStatus status = getStatus();
String msg = MessageFormat.format(
"Failed to install some breakpoints in the module [{0}]. Errors: \n", module.getName());
if (status.isMultiStatus()) {
for (IStatus s : ((MultiStatus) status).getChildren())
msg += s.getMessage() + "\n";
} else
msg += status.getMessage();
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, msg); }
}
// We should do these regardless of whether installing
// breakpoints succeeded or not.
setStartupBreakpoint(module, new RequestMonitor(getExecutor(), null) {
@Override
protected void handleCompleted() {
// do this regardless of status of installing entry
// breakpoint
// as it's expected the startup bp not resolvable in all
// modules.
//
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "resume process after module load event ..."); }
if (requireResume)
((ExecutionDMC) executionDMC).resume(new RequestMonitor(getExecutor(), null));
}
});
}
});
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
/**
* Check if resume is required after handling load/unload of the given module.
*
* @param module
* @return
*/
private boolean requireResume(ModuleDMC module) {
boolean requireResume = true;
Object propvalue = module.getProperties().get(IModuleProperty.PROP_RESUME);
if (propvalue != null)
if (propvalue instanceof Boolean)
requireResume = (Boolean) propvalue;
return requireResume;
}
/**
* Set breakpoint at startup point specified by user.
*
* @param module
* @param rm
*/
protected void setStartupBreakpoint(ModuleDMC module, RequestMonitor rm) {
EDCLaunch launch = EDCLaunch.getLaunchForSession(getSession().getId());
ILaunchConfiguration launchConfig = launch.getLaunchConfiguration();
if (startupBreakpointModule.get(launchConfig) != null) {
// already set in a module for this launch configuration, no need to try it for any other module
rm.done();
return;
}
String startupStopAt = launch.getStartupStopAtPoint();
// Is this even requested by user ?
if (startupStopAt == null) {
rm.done();
return;
}
// Ask target environment whether it wants us to try installing
// startup breakpoint in the module.
ITargetEnvironment te = getTargetEnvironmentService();
if (! te.needStartupBreakpointInExecutable(module.getName())) {
rm.done();
return;
}
IAddress iaddr = null;
long address = 0;
// Check if the point is absolute runtime address.
//
try {
// first check if it's decimal number
address = Long.parseLong(startupStopAt);
} catch (NumberFormatException e) {
// then check if it's hex
if (startupStopAt.toLowerCase().startsWith("0x")) {
try {
address = Long.parseLong(startupStopAt.substring(2), 16);
} catch (IllegalFormatException e1) {
// ignore
}
}
}
if (address != 0) {
iaddr = new Addr32(address);
// Assume it is a link-time address first. Run-time addresses are not predictable across launches.
IAddress runAddr = module.toRuntimeAddress(iaddr);
if (module.containsAddress(runAddr)) {
iaddr = runAddr;
} else {
// Try for a runtime address.
if (!module.containsAddress(iaddr)) {
// address not in the module, don't bother.
// This is to ensure the address breakpoint is installed
// after the container module is loaded.
iaddr = null;
}
}
} else {
// the point is a symbol
Symbols symService = getService(Symbols.class);
List<IAddress> addrs = symService.getFunctionAddress(module, startupStopAt);
if (addrs.size() > 0)
// just choose the first one
iaddr = addrs.get(0);
}
if (iaddr == null) {
EDCDebugger.getMessageLogger().logError(
"Could not resolve startup breakpoint: "+ startupStopAt, null);
rm.done();
} else {
// The breakpoint is resolved in the module.
startupBreakpointModule.put(launchConfig, module);
IExecutionDMContext exe_dmc = DMContexts.getAncestorOfType(module, IExecutionDMContext.class);
setTempBreakpoint(exe_dmc, iaddr, rm);
}
}
@DsfServiceEventHandler
public void eventHandler_uninstallBreakpointsForModule(ModuleUnloadedDMEvent e) {
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArgs(new Object[] { e.getClass().getName(), e })); }
// An existing module (including main exe) is unloaded. Uninstall
// breakpoints for it.
ModuleUnloadedEvent event = (ModuleUnloadedEvent) e;
final ExecutionDMC executionDMC = (ExecutionDMC)event.getExecutionDMC();
final ModuleDMC module = (ModuleDMC) e.getUnloadedModuleContext();
/*
* If module containing startup break is unloaded, mark the startup
* break as gone so that we can reinstall it the next time the module is
* loaded again in the same debug session.
*/
if (startupBreakpointModule != null &&
startupBreakpointModule.equals(module))
startupBreakpointModule = null;
final boolean requireResume = requireResume(module);
BreakpointsMediator2 bm = getService(BreakpointsMediator2.class);
IBreakpointsTargetDMContext bt_dmc = DMContexts.getAncestorOfType(e.getUnloadedModuleContext(),
IBreakpointsTargetDMContext.class);
bm.stopTrackingBreakpoints(bt_dmc, new RequestMonitor(getExecutor(), null) {
@Override
protected void handleFailure() {
// super will just log the error.
super.handleFailure();
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "uninstalling breakpoints failed"); }
}
@Override
protected void handleSuccess() {
super.handleSuccess();
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().trace(null, "breakpoints uninstalled and resume process..."); }
if (requireResume)
executionDMC.resume(new RequestMonitor(getExecutor(), null));
}
});
if (EDCTrace.BREAKPOINTS_TRACE_ON) { EDCTrace.getTrace().traceExit(null); }
}
protected void addBreakpointProblemMarker(final IBreakpointDMContext targetBP,
final String description, final int severity) {
BreakpointsMediator2 bmService = getService(BreakpointsMediator2.class);
if (bmService == null)
return;
final IBreakpoint breakpoint = bmService.getPlatformBreakpoint(null, targetBP);
if (breakpoint == null)
return;
if (! (breakpoint instanceof ICLineBreakpoint))
return;
new Job("Add Breakpoint Problem Marker") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
// If we have already have a problem marker on this breakpoint
// we should remove it first.
IMarker marker = fBreakpointMarkers.remove(targetBP);
if (marker != null) {
try {
marker.delete();
} catch (CoreException e) {
}
}
ICLineBreakpoint lineBreakpoint = (ICLineBreakpoint) breakpoint;
try {
// Locate the workspace resource via the breakpoint marker
IMarker breakpoint_marker = lineBreakpoint.getMarker();
IResource resource = breakpoint_marker.getResource();
// Add a problem marker to the resource
IMarker problem_marker = resource.createMarker(BreakpointProblems.BREAKPOINT_PROBLEM_MARKER_ID);
int line_number = lineBreakpoint.getLineNumber();
problem_marker.setAttribute(IMarker.LOCATION, String.valueOf(line_number));
problem_marker.setAttribute(IMarker.MESSAGE, description);
problem_marker.setAttribute(IMarker.SEVERITY, severity);
problem_marker.setAttribute(IMarker.LINE_NUMBER, line_number);
// And save the baby
fBreakpointMarkers.put(targetBP, problem_marker);
} catch (CoreException e) {
}
return Status.OK_STATUS;
}
}.schedule();
}
/**
* Remove problem marker added for the given target breakpoint.
* Note this may be called when debug session is shutdown.
*
* @param breakpoint
*/
protected void removeBreakpointProblemMarker(final IBreakpointDMContext breakpoint) {
final IMarker marker = fBreakpointMarkers.remove(breakpoint);
if (marker == null)
return;
new Job("Remove Breakpoint Problem Marker") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
marker.delete();
} catch (CoreException e) {
}
return Status.OK_STATUS;
}
}.schedule();
}
/**
* Evaluate condition of given breakpoint, if any.
*
* @param context
* execution context in which to evaluate the condition.
* @param bp
* the breakpoint.
* @param drm
* DataRequestMonitor that contains result indicating whether
* to stop execution of debugged program. The result value is
* true if <br>
* 1. the breakpoint has no condition, or <br>
* 2. the breakpoint condition is invalid in syntax, or <br>
* 3. the breakpoint condition cannot be resolved, or <br>
* 4. the breakpoint condition is true.<br>
* Otherwise the result in the drm is false.
*
*/
public void evaluateBreakpointCondition(IExecutionDMContext context, final BreakpointDMData bp, final DataRequestMonitor<Object> drm) {
final String expr = bp.getCondition();
if (expr == null || expr.length() == 0) {
bp.incrementHitCount();
drm.setData(bp.getHitCount() > bp.getIgnoreCount() ? bp : false);
drm.done();
return;
}
Stack stackService = getService(Stack.class);
stackService.getTopFrame(context, new DataRequestMonitor<IFrameDMContext>(getExecutor(), drm) {
@Override
protected void handleCompleted() {
if (!isSuccess()) { // fail to get frame, namely cannot
// evaluate the condition
bp.incrementHitCount();
drm.setData(bp.getHitCount() > bp.getIgnoreCount() ? bp : false);
drm.done();
} else {
Expressions exprService = getService(Expressions.class);
IEDCExpression expression = (IEDCExpression) exprService.createExpression(getData(), expr);
FormattedValueDMContext fvc = exprService.getFormattedValueContext(expression,
IFormattedValues.NATURAL_FORMAT);
FormattedValueDMData value = expression.getFormattedValue(fvc);
/*
* honor the breakpoint if the condition is true or
* invalid.
*/
String vstr = value.getFormattedValue();
if (! vstr.equals("true") && ! vstr.equals("false")) //$NON-NLS-1$ //$NON-NLS-2$
addBreakpointProblemMarker(bp.getContext(), "Breakpoint condition failed to resolve to boolean: " + vstr, IMarker.SEVERITY_WARNING);
else // remove any problem marker
removeBreakpointProblemMarker(bp.getContext());
if (!vstr.equals("false"))
{
bp.incrementHitCount();
drm.setData(bp.getHitCount() > bp.getIgnoreCount() ? bp : false);
}
else
drm.setData(false); //$NON-NLS-1$
drm.done();
}
}
});
}
}