diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDIDebugModel.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDIDebugModel.java index 43539805dc7..e02da67b6d6 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDIDebugModel.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDIDebugModel.java @@ -696,6 +696,52 @@ public class CDIDebugModel { return new CWatchpoint(resource, attributes, register); } + /** + * Creates and returns a watchpoint for the source defined by the given + * source handle, at the given expression. The marker associated with the + * watchpoint will be created on the specified resource. + * + * @param sourceHandle + * the handle to the watchpoint source + * @param resource + * the resource on which to create the associated watchpoint + * marker + * @param type + * a type constant from ICBreakpointType + * @param writeAccess + * whether this is write watchpoint + * @param readAccess + * whether this is read watchpoint + * @param expression + * the expression on which the watchpoint is set + * @param enabled + * whether to enable or disable this breakpoint + * @param ignoreCount + * the number of times this breakpoint will be ignored + * @param condition + * the breakpoint condition + * @param register + * whether to add this breakpoint to the breakpoint manager + * @return a watchpoint + * @throws CoreException + * if this method fails. Reasons include: + * + * + * @since 7.3 + */ + public static ICWatchpoint createWatchpoint(String sourceHandle, IResource resource, int type, boolean writeAccess, + boolean readAccess, String expression, boolean enabled, int ignoreCount, String condition, boolean register) + throws CoreException { + HashMap attributes = new HashMap(10); + setWatchPointAttributes(attributes, sourceHandle, resource, type, writeAccess, readAccess, expression, "", //$NON-NLS-1$ + BigInteger.ZERO, enabled, ignoreCount, condition); + return new CWatchpoint(resource, attributes, register); + } + /** * Creates and returns a watchpoint for the source defined by the given * source handle, at the given expression. The marker associated with the @@ -850,6 +896,47 @@ public class CDIDebugModel { attributes.put(ICWatchpoint.WRITE, Boolean.valueOf(writeAccess)); } + /** + * Helper function for setting common watchpoint attributes. + * + * @param attributes + * Map to write the attributes into. + * @param sourceHandle + * the handle to the watchpoint source + * @param resource + * the resource on which to create the associated watchpoint + * marker + * @param type + * a type constant from ICBreakpointType + * @param writeAccess + * whether this is write watchpoint + * @param readAccess + * whether this is read watchpoint + * @param expression + * the expression on which the watchpoint is set + * @param memorySpace + * the memory space in which the watchpoint is set + * @param range + * the range of the watchpoint in addressable units + * @param enabled + * whether to enable or disable this breakpoint + * @param ignoreCount + * the number of times this breakpoint will be ignored + * @param condition + * the breakpoint condition + * @param register + * whether to add this breakpoint to the breakpoint manager + * + * @since 7.3 + */ + public static void setWatchPointAttributes(Map attributes, String sourceHandle, IResource resource, + int type, boolean writeAccess, boolean readAccess, String expression, String memorySpace, BigInteger range, + boolean enabled, int ignoreCount, String condition) { + setWatchPointAttributes(attributes, sourceHandle, resource, + writeAccess, readAccess, expression, memorySpace, range, enabled, ignoreCount, condition); + attributes.put(ICBreakpointType.TYPE, type); + } + /** * Creates and returns a breakpoint for the function defined by the given * name. The marker associated with the breakpoint will be created on the diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java index ed986b883e7..f88761ee33a 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java @@ -357,6 +357,7 @@ public class CDebugUtils { appendWatchMemorySpace(wp2, label); appendWatchRange(wp2, label); } + appendBreakpointType(watchpoint, label); appendIgnoreCount(watchpoint, label); appendCondition(watchpoint, label); return label.toString(); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/ServicesLaunchSequence.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/ServicesLaunchSequence.java index ad15fc60642..02d071d3ded 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/ServicesLaunchSequence.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/ServicesLaunchSequence.java @@ -35,6 +35,7 @@ import org.eclipse.cdt.dsf.mi.service.CSourceLookup; import org.eclipse.cdt.dsf.mi.service.IMIBackend; import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager; +import org.eclipse.cdt.dsf.mi.service.MIBreakpointsSynchronizer; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.IProgressMonitor; @@ -130,6 +131,11 @@ public class ServicesLaunchSequence extends Sequence { requestMonitor.done(); } }}, + new Step() { @Override + public void execute(final RequestMonitor requestMonitor) { + // Create breakpoint synchronization service. + fLaunch.getServiceFactory().createService(MIBreakpointsSynchronizer.class, fSession).initialize(requestMonitor); + }}, }; DsfSession fSession; diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_4.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_4.java new file mode 100644 index 00000000000..c58005eb554 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_4.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (c) 2012 Mentor Graphics 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: + * Mentor Graphics - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.service; + +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +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.command.ICommandControl; +import org.eclipse.cdt.dsf.debug.service.command.IEventListener; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.mi.service.IMICommandControl; +import org.eclipse.cdt.dsf.mi.service.MIBreakpointDMData; +import org.eclipse.cdt.dsf.mi.service.MIBreakpoints; +import org.eclipse.cdt.dsf.mi.service.MIBreakpointsSynchronizer; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; +import org.eclipse.cdt.dsf.mi.service.command.output.MIConst; +import org.eclipse.cdt.dsf.mi.service.command.output.MINotifyAsyncOutput; +import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord; +import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; +import org.eclipse.cdt.dsf.mi.service.command.output.MIResult; +import org.eclipse.cdt.dsf.mi.service.command.output.MITuple; +import org.eclipse.cdt.dsf.mi.service.command.output.MIValue; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +/** + * Breakpoints service for GDB 7.4. + * Using breakpoint notifications introduced in 7.4 supports synchronization between the breakpoints + * set from the GDB console and the Breakpoints view as well as the tracepoints reported form trace files. + * + * @since 4.2 + */ +public class GDBBreakpoints_7_4 extends GDBBreakpoints_7_2 implements IEventListener { + + // Breakpoint notifications + private static final String BREAKPOINT_PREFIX = "breakpoint-"; //$NON-NLS-1$ + private static final String BREAKPOINT_CREATED = BREAKPOINT_PREFIX + "created"; //$NON-NLS-1$ + private static final String BREAKPOINT_MODIFIED = BREAKPOINT_PREFIX + "modified"; //$NON-NLS-1$ + private static final String BREAKPOINT_DELETED = BREAKPOINT_PREFIX + "deleted"; //$NON-NLS-1$ + + private IMICommandControl fConnection; + + public GDBBreakpoints_7_4(DsfSession session) { + super(session); + } + + @Override + public void initialize(final RequestMonitor rm) { + super.initialize(new ImmediateRequestMonitor(rm) { + @Override + protected void handleSuccess() { + doInitialize(rm); + } + }); + } + + private void doInitialize(final RequestMonitor rm) { + fConnection = getServicesTracker().getService(IMICommandControl.class); + if (fConnection == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Service is not available")); //$NON-NLS-1$ + rm.done(); + return; + } + fConnection.addEventListener(this); + + // Register this service + register(new String[] { IBreakpoints.class.getName(), + IBreakpointsExtension.class.getName(), + MIBreakpoints.class.getName(), + GDBBreakpoints_7_0.class.getName(), + GDBBreakpoints_7_2.class.getName(), + GDBBreakpoints_7_4.class.getName() }, + new Hashtable()); + + rm.done(); + } + + @Override + public void shutdown(RequestMonitor requestMonitor) { + ICommandControl control = getCommandControl(); + if (control != null) { + control.removeEventListener(this); + } + unregister(); + super.shutdown(requestMonitor); + } + + @Override + public void eventReceived(Object output) { + if (output instanceof MIOutput) { + MIBreakpointsSynchronizer bs = getServicesTracker().getService(MIBreakpointsSynchronizer.class); + if (bs != null) { + MIOOBRecord[] records = ((MIOutput)output).getMIOOBRecords(); + for(MIOOBRecord r : records) { + if (r instanceof MINotifyAsyncOutput) { + MINotifyAsyncOutput notifyOutput = (MINotifyAsyncOutput)r; + String asyncClass = notifyOutput.getAsyncClass(); + if (BREAKPOINT_CREATED.equals(asyncClass)) { + MIBreakpoint bpt = getMIBreakpointFromOutput(notifyOutput); + if (bpt != null) + bs.targetBreakpointCreated(bpt); + } + else if (BREAKPOINT_DELETED.equals(asyncClass)) { + int id = getMIBreakpointIdFromOutput(notifyOutput); + if (id != 0) + bs.targetBreakpointDeleted(id); + } + else if (BREAKPOINT_MODIFIED.equals(asyncClass)) { + MIBreakpoint bpt = getMIBreakpointFromOutput(notifyOutput); + if (bpt != null) + bs.targetBreakpointModified(bpt); + } + } + } + } + } + } + + private IMICommandControl getCommandControl() { + return fConnection; + } + + private MIBreakpoint getMIBreakpointFromOutput(MINotifyAsyncOutput notifyOutput) { + MIBreakpoint bpt = null; + MIResult[] results = notifyOutput.getMIResults(); + for(int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + if (var.equals("bkpt")) { //$NON-NLS-1$ + if (val instanceof MITuple) { + bpt = new MIBreakpoint((MITuple)val); + } + } + } + return bpt; + } + + private int getMIBreakpointIdFromOutput(MINotifyAsyncOutput notifyOutput) { + MIResult[] results = notifyOutput.getMIResults(); + for(int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + if (var.equals("id") && val instanceof MIConst) { //$NON-NLS-1$ + try { + return Integer.parseInt(((MIConst)val).getCString().trim()); + } + catch(NumberFormatException e) { + GdbPlugin.log(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Invalid breakpoint id")); //$NON-NLS-1$ + } + } + } + return 0; + } + + @Override + protected void addBreakpoint(IBreakpointsTargetDMContext context, Map attributes, DataRequestMonitor finalRm) { + MIBreakpointsSynchronizer bs = getServicesTracker().getService(MIBreakpointsSynchronizer.class); + if (bs != null) { + // Skip the breakpoints set from the console or from outside of Eclipse + // because they are already installed on the target. + MIBreakpoint miBpt = bs.getTargetBreakpoint(context, attributes); + if (miBpt != null) { + bs.removeCreatedTargetBreakpoint(context, miBpt); + MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(miBpt); + getBreakpointMap(context).put(newBreakpoint.getNumber(), newBreakpoint); + IBreakpointDMContext dmc = new MIBreakpointDMContext(this, new IDMContext[] { context }, newBreakpoint.getNumber()); + finalRm.setData(dmc); + + getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); + + finalRm.done(); + return; + } + } + super.addBreakpoint(context, attributes, finalRm); + } + + @Override + protected void addTracepoint(IBreakpointsTargetDMContext context, Map attributes, DataRequestMonitor drm) { + MIBreakpointsSynchronizer bs = getServicesTracker().getService(MIBreakpointsSynchronizer.class); + if (bs != null) { + // Skip the breakpoints set from the console or from outside of Eclipse + // because they are already installed on the target. + MIBreakpoint miBpt = bs.getTargetBreakpoint(context, attributes); + if (miBpt != null) { + bs.removeCreatedTargetBreakpoint(context, miBpt); + MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(miBpt); + getBreakpointMap(context).put(newBreakpoint.getNumber(), newBreakpoint); + IBreakpointDMContext dmc = new MIBreakpointDMContext(this, new IDMContext[] { context }, newBreakpoint.getNumber()); + drm.setData(dmc); + + getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); + + drm.done(); + return; + } + } + super.addTracepoint(context, attributes, drm); + } + + @Override + protected void addWatchpoint(IBreakpointsTargetDMContext context, Map attributes, DataRequestMonitor drm) { + MIBreakpointsSynchronizer bs = getServicesTracker().getService(MIBreakpointsSynchronizer.class); + if (bs != null) { + // Skip the breakpoints set from the console or from outside of Eclipse + // because they are already installed on the target. + MIBreakpoint miBpt = bs.getTargetBreakpoint(context, attributes); + if (miBpt != null) { + bs.removeCreatedTargetBreakpoint(context, miBpt); + MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(miBpt); + getBreakpointMap(context).put(newBreakpoint.getNumber(), newBreakpoint); + IBreakpointDMContext dmc = new MIBreakpointDMContext(this, new IDMContext[] { context }, newBreakpoint.getNumber()); + drm.setData(dmc); + + getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); + + drm.done(); + return; + } + } + super.addWatchpoint(context, attributes, drm); + } + + @Override + protected void deleteBreakpointFromTarget(IBreakpointsTargetDMContext context, int reference, RequestMonitor finalRm) { + MIBreakpointsSynchronizer bs = getServicesTracker().getService(MIBreakpointsSynchronizer.class); + if (bs != null) { + // Do nothing if the breakpoint is deleted from the console. + if (bs.isTargetBreakpointDeleted(context, reference, true)) { + finalRm.done(); + return; + } + } + super.deleteBreakpointFromTarget(context, reference, finalRm); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java index 27501dff4ee..9b9e772cd0c 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java @@ -37,6 +37,7 @@ import org.eclipse.cdt.dsf.mi.service.CSourceLookup; import org.eclipse.cdt.dsf.mi.service.IMIBackend; import org.eclipse.cdt.dsf.mi.service.MIBreakpoints; import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager; +import org.eclipse.cdt.dsf.mi.service.MIBreakpointsSynchronizer; import org.eclipse.cdt.dsf.mi.service.MIDisassembly; import org.eclipse.cdt.dsf.mi.service.MIExpressions; import org.eclipse.cdt.dsf.mi.service.MIMemory; @@ -106,6 +107,9 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { } } } + else if (MIBreakpointsSynchronizer.class.isAssignableFrom(clazz)) { + return (V)createBreakpointsSynchronizerService(session); + } return super.createService(clazz, session); } @@ -116,6 +120,9 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { @Override protected IBreakpoints createBreakpointService(DsfSession session) { + if (GDB_7_4_VERSION.compareTo(fVersion) <= 0) { + return new GDBBreakpoints_7_4(session); + } // This service is available for GDB 7.2 but there is a pre-release of GDB that // supports the same features and has version of 6.8.50.20090414 if (GDB_7_2_VERSION.compareTo(fVersion) <= 0 || "6.8.50.20090414".equals(fVersion)) { //$NON-NLS-1$ @@ -237,4 +244,11 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { } return new GDBHardwareAndOS(session); } + + /** + * @since 4.2 + */ + protected MIBreakpointsSynchronizer createBreakpointsSynchronizerService(DsfSession session) { + return new MIBreakpointsSynchronizer(session); + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java index dcf41fb7361..55caaebfa8d 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpoints.java @@ -20,6 +20,7 @@ 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; @@ -913,26 +914,16 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints, I return; } - final Step deleteBreakpointStep = new Step() { - @Override - public void execute(final RequestMonitor rm) { - // Queue the command - fConnection.queueCommand( - fCommandFactory.createMIBreakDelete(context, new int[] { reference }), - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - getSession().dispatchEvent(new BreakpointRemovedEvent(dmc), getProperties()); - contextBreakpoints.remove(reference); - } - rm.done(); - } - }); - } - }; - - fRunControl.executeWithTargetAvailable(context, new Step[] { deleteBreakpointStep }, finalRm); + 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(); + } + }); } // ------------------------------------------------------------------------- @@ -1279,6 +1270,24 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints, I fRunControl.executeWithTargetAvailable(context, new Step[] { disableBreakpointStep }, finalRm); } + /** + * This method deletes the target breakpoint with the given reference number. + * @since 4.2 + */ + protected void deleteBreakpointFromTarget(final IBreakpointsTargetDMContext context, final int reference, RequestMonitor finalRm) { + final Step deleteBreakpointStep = new Step() { + @Override + public void execute(final RequestMonitor rm) { + // Queue the command + fConnection.queueCommand( + fCommandFactory.createMIBreakDelete(context, new int[] { reference }), + new DataRequestMonitor(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. @@ -1334,5 +1343,18 @@ public class MIBreakpoints extends AbstractDsfService implements IBreakpoints, I } fBreakpointHitMap.remove(container); } - + + /** + * Returns a breakpoint target context for given breakpoint number. + * @since 4.2 + */ + protected IBreakpointsTargetDMContext getBreakpointTargetContext(int reference) { + for (IBreakpointsTargetDMContext context : fBreakpoints.keySet()) { + Map map = fBreakpoints.get(context); + if (map != null && map.keySet().contains(Integer.valueOf(reference))) { + return context; + } + } + return null; + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsManager.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsManager.java index 65b26f7d2c0..629014d30a6 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsManager.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsManager.java @@ -34,6 +34,7 @@ import org.eclipse.cdt.debug.core.model.ICBreakpoint; import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; import org.eclipse.cdt.debug.core.model.ICBreakpointType; import org.eclipse.cdt.debug.core.model.ICEventBreakpoint; +import org.eclipse.cdt.debug.core.model.ICFunctionBreakpoint; import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; import org.eclipse.cdt.debug.core.model.ICTracepoint; import org.eclipse.cdt.debug.core.model.ICWatchpoint; @@ -41,6 +42,7 @@ 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.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.ThreadSafe; @@ -82,6 +84,7 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.ISchedulingRule; @@ -104,7 +107,19 @@ import com.ibm.icu.text.MessageFormat; */ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener { - // Note: Find a way to import this (careful of circular dependencies) + /** + * A listener is notified by {@link MIBreakpointsManager} when + * the breakpoints tracking starts or stops. + * @since 4.2 + */ + public interface IMIBreakpointsTrackingListener { + + public void breakpointTrackingStarted(IBreakpointsTargetDMContext bpTargetDMC); + + public void breakpointTrackingStopped(IBreakpointsTargetDMContext bpTargetDMC); + } + + // Note: Find a way to import this (careful of circular dependencies) public final static String GDB_DEBUG_MODEL_ID = "org.eclipse.cdt.dsf.gdb"; //$NON-NLS-1$ // Extra breakpoint attributes @@ -177,6 +192,8 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo private Map fBreakpointMarkerProblems = new HashMap(); + private ListenerList fTrackingListeners = new ListenerList(); + /////////////////////////////////////////////////////////////////////////// // String constants /////////////////////////////////////////////////////////////////////////// @@ -284,6 +301,7 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo getSession().removeServiceEventListener(this); fBreakpointManager.removeBreakpointListener(this); fBreakpointManager.removeBreakpointManagerListener(this); + fTrackingListeners.clear(); // Cleanup the breakpoints that are still installed by the service. // Use a counting monitor which will call mom to complete the shutdown @@ -369,7 +387,16 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo getExecutor().submit(new Runnable() { @Override public void run() { - installInitialBreakpoints(dmc, rm); + installInitialBreakpoints(dmc, new RequestMonitor(ImmediateExecutor.getInstance(), rm) { + @Override + protected void handleSuccess() { + // Notify breakpoints tracking listeners that the tracking is started. + for (Object o : fTrackingListeners.getListeners()) { + ((IMIBreakpointsTrackingListener)o).breakpointTrackingStarted(dmc); + } + rm.done(); + }; + }); } }); @@ -491,6 +518,10 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo fBreakpointIDs.remove(dmc); fTargetBPs.remove(dmc); fBreakpointThreads.remove(dmc); + // Notify breakpoints tracking listeners that the tracking is stopped. + for (Object o : fTrackingListeners.getListeners()) { + ((IMIBreakpointsTrackingListener)o).breakpointTrackingStopped(dmc); + } rm.done(); } }; @@ -549,7 +580,9 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo } // Ensure the breakpoint has a valid debugger source path - if (breakpoint instanceof ICLineBreakpoint && !(breakpoint instanceof ICAddressBreakpoint)) { + if (breakpoint instanceof ICLineBreakpoint + && !(breakpoint instanceof ICAddressBreakpoint) + && !(breakpoint instanceof ICFunctionBreakpoint)) { String debuggerPath = (String) attributes.get(ATTR_DEBUGGER_PATH); if (debuggerPath == null || debuggerPath == NULL_STRING) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, NO_DEBUGGER_PATH, null)); @@ -719,8 +752,10 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo * @param dmc * @param breakpoint * @param rm + * + * @since 4.2 */ - private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, + public void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, final ICBreakpoint breakpoint, final RequestMonitor rm) { // Retrieve the breakpoint maps @@ -1809,16 +1844,6 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo properties.put(MIBreakpoints.PASS_COUNT, attributes.get(ICTracepoint.PASS_COUNT)); } - // checks for the breakpoint type, and adds the hardware/temporary flags - Object breakpointType = attributes.get(ICBreakpointType.TYPE); - if(breakpointType != null) { - if(breakpointType instanceof Integer) { - boolean isHardware = ((Integer) breakpointType & ICBreakpointType.HARDWARE) == ICBreakpointType.HARDWARE; - boolean isTemporary = ((Integer) breakpointType & ICBreakpointType.TEMPORARY) == ICBreakpointType.TEMPORARY; - properties.put(MIBreakpointDMData.IS_HARDWARE, isHardware); - properties.put(MIBreakpointDMData.IS_TEMPORARY, isTemporary); - } - } } else if (breakpoint instanceof ICEventBreakpoint) { properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.CATCHPOINT); @@ -1845,6 +1870,17 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo properties.put(MIBreakpoints.IS_ENABLED, attributes.get(ICBreakpoint.ENABLED)); properties.put(MIBreakpointDMData.THREAD_ID, attributes.get(ATTR_THREAD_ID)); + // checks for the breakpoint type, and adds the hardware/temporary flags + Object breakpointType = attributes.get(ICBreakpointType.TYPE); + if(breakpointType != null) { + if(breakpointType instanceof Integer) { + boolean isHardware = ((Integer) breakpointType & ICBreakpointType.HARDWARE) == ICBreakpointType.HARDWARE; + boolean isTemporary = ((Integer) breakpointType & ICBreakpointType.TEMPORARY) == ICBreakpointType.TEMPORARY; + properties.put(MIBreakpointDMData.IS_HARDWARE, isHardware); + properties.put(MIBreakpointDMData.IS_TEMPORARY, isTemporary); + } + } + // Adjust for "skip-all" // Tracepoints are not affected by "skip-all" if (!(breakpoint instanceof ICTracepoint ) && !fBreakpointManager.isEnabled()) { @@ -1928,4 +1964,18 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo } return true; } + + /** + * @since 4.2 + */ + public void addBreakpointsTrackingListener(IMIBreakpointsTrackingListener listener) { + fTrackingListeners.add(listener); + } + + /** + * @since 4.2 + */ + public void removeBreakpointsTrackingListener(IMIBreakpointsTrackingListener listener) { + fTrackingListeners.remove(listener); + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsSynchronizer.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsSynchronizer.java new file mode 100644 index 00000000000..aa74559bdb4 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointsSynchronizer.java @@ -0,0 +1,1278 @@ +/******************************************************************************* + * Copyright (c) 2012 Mentor Graphics 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: + * Mentor Graphics - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.mi.service; + +import java.io.File; +import java.math.BigInteger; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.debug.core.CDIDebugModel; +import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager; +import org.eclipse.cdt.debug.core.model.ICAddressBreakpoint; +import org.eclipse.cdt.debug.core.model.ICBreakpoint; +import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; +import org.eclipse.cdt.debug.core.model.ICBreakpointType; +import org.eclipse.cdt.debug.core.model.ICFunctionBreakpoint; +import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; +import org.eclipse.cdt.debug.core.model.ICTracepoint; +import org.eclipse.cdt.debug.core.model.ICWatchpoint; +import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMData; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.cdt.dsf.debug.service.IDsfBreakpointExtension; +import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +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.ISourceLookup; +import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.internal.tracepointactions.CollectAction; +import org.eclipse.cdt.dsf.gdb.internal.tracepointactions.EvaluateAction; +import org.eclipse.cdt.dsf.gdb.internal.tracepointactions.ITracepointAction; +import org.eclipse.cdt.dsf.gdb.internal.tracepointactions.TracepointActionManager; +import org.eclipse.cdt.dsf.gdb.internal.tracepointactions.WhileSteppingAction; +import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext; +import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager.IMIBreakpointsTrackingListener; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; +import org.eclipse.cdt.dsf.service.AbstractDsfService; +import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage; +import org.osgi.framework.BundleContext; + +/** + * Provides synchronization between breakpoints set from outside of the Eclipse breakpoint + * framework (GDB console, trace files, etc.) and the Breakpoints view. + * @since 4.2 + */ +public class MIBreakpointsSynchronizer extends AbstractDsfService implements IMIBreakpointsTrackingListener { + + // Catchpoint expressions + private static final String CE_EXCEPTION_CATCH = "exception catch"; //$NON-NLS-1$ + private static final String CE_EXCEPTION_THROW = "exception throw"; //$NON-NLS-1$ + + // GDB tracepoint commands + private static final String TC_COLLECT = "collect "; //$NON-NLS-1$ + private static final String TC_TEVAL = "teval "; //$NON-NLS-1$ + private static final String TC_WHILE_STEPPING = "while-stepping "; //$NON-NLS-1$ + private static final String TC_END = "end"; //$NON-NLS-1$ + + private IMICommandControl fConnection; + private MIBreakpoints fBreakpointsService; + private MIBreakpointsManager fBreakpointsManager; + + /** + * Collection of the target contexts that are being tracked. + */ + private Set fTrackedTargets; + + /** + * Collection of breakpoints created from the GDB console or outside of Eclipse + */ + private Map> fCreatedTargetBreakpoints; + + /** + * Collection of breakpoints deleted from the GDB console or outside of Eclipse + */ + private Map> fDeletedTargetBreakpoints; + + /** + * Collection of pending breakpoint modifications + */ + private Map> fPendingModifications; + + public MIBreakpointsSynchronizer(DsfSession session) { + super(session); + fTrackedTargets = new HashSet(); + fCreatedTargetBreakpoints = new HashMap>(); + fDeletedTargetBreakpoints = new HashMap>(); + fPendingModifications = new HashMap>(); + } + + @Override + protected BundleContext getBundleContext() { + return GdbPlugin.getBundleContext(); + } + + @Override + public void initialize(final RequestMonitor rm) { + super.initialize(new ImmediateRequestMonitor(rm) { + @Override + protected void handleSuccess() { + doInitialize(rm); + } + }); + } + + private void doInitialize(final RequestMonitor rm) { + fConnection = getServicesTracker().getService(IMICommandControl.class); + fBreakpointsService = getServicesTracker().getService(MIBreakpoints.class); + fBreakpointsManager = getServicesTracker().getService(MIBreakpointsManager.class); + if (fConnection == null || fBreakpointsService == null && fBreakpointsManager == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Service is not available")); //$NON-NLS-1$ + rm.done(); + return; + } + fBreakpointsManager.addBreakpointsTrackingListener(this); + getSession().addServiceEventListener(this, null); + + // Register this service + register(new String[] { + MIBreakpointsSynchronizer.class.getName() + }, + new Hashtable()); + + rm.done(); + } + + @Override + public void shutdown(RequestMonitor rm) { + fTrackedTargets.clear(); + fCreatedTargetBreakpoints.clear(); + fDeletedTargetBreakpoints.clear(); + fPendingModifications.clear(); + getSession().removeServiceEventListener(this); + MIBreakpointsManager bm = getBreakpointsManager(); + if (bm != null) { + bm.removeBreakpointsTrackingListener(this); + } + unregister(); + super.shutdown( rm ); + } + + @Override + public void breakpointTrackingStarted(IBreakpointsTargetDMContext bpTargetDMC) { + fTrackedTargets.add(bpTargetDMC); + } + + @Override + public void breakpointTrackingStopped(IBreakpointsTargetDMContext bpTargetDMC) { + fTrackedTargets.remove(bpTargetDMC); + } + + private IMICommandControl getCommandControl() { + return fConnection; + } + + private MIBreakpoints getBreakpointsService() { + return fBreakpointsService; + } + + private MIBreakpointsManager getBreakpointsManager() { + return fBreakpointsManager; + } + + public void targetBreakpointCreated(final MIBreakpoint miBpt) { + if (isCatchpoint(miBpt)) + return; + ICommandControlService commandControl = getCommandControl(); + MIBreakpoints breakpointsService = getBreakpointsService(); + final MIBreakpointsManager bm = getBreakpointsManager(); + if (commandControl == null || breakpointsService == null || bm == null) + return; + + final IBreakpointsTargetDMContext bpTargetDMC = getBreakpointsTargetContext(commandControl, miBpt); + if (bpTargetDMC == null) + return; + + // Store the target breakpoint data + Map contextBreakpoints = breakpointsService.getBreakpointMap(bpTargetDMC); + if (contextBreakpoints == null) { + contextBreakpoints = breakpointsService.createNewBreakpointMap(bpTargetDMC); + } + contextBreakpoints.put(Integer.valueOf(miBpt.getNumber()), new MIBreakpointDMData(miBpt)); + + // Store the created target breakpoint to prevent setting it again on the target + // when addBreakpoint() is called. + Map targetMap = fCreatedTargetBreakpoints.get(bpTargetDMC); + if (targetMap == null) { + targetMap = new HashMap(); + fCreatedTargetBreakpoints.put(bpTargetDMC, targetMap); + } + targetMap.put(Integer.valueOf(miBpt.getNumber()), miBpt); + + // Convert the debug info file path into the file path in the local file system + String debuggerPath = getFileName(miBpt); + getSource( + bpTargetDMC, + debuggerPath, + new DataRequestMonitor(getExecutor(), null) { + @Override + @ConfinedToDsfExecutor( "fExecutor" ) + protected void handleSuccess() { + String fileName = getData(); + if (fileName == null) + fileName = getFileName(miBpt); + // Try to find matching platform breakpoint + ICBreakpoint plBpt = getPlatformBreakpoint(miBpt, fileName); + String threadId = miBpt.getThreadId(); + boolean isThreadSpecific = threadId != null && !threadId.isEmpty() && !"0".equals(threadId); //$NON-NLS-1$ + try { + if (plBpt == null) { + // If matching platform breakpoint doesn't exist create a new one + plBpt = createPlatformBreakpoint(fileName, miBpt); + // If the target breakpoint is thread specific, update thread filters + if (isThreadSpecific) { + setThreadSpecificBreakpoint(bpTargetDMC, plBpt, miBpt); + } + } + else { + // The corresponding platform breakpoint already exists. + // If the breakpoint tracking has already started we need + // to notify MIBreakpointsManager which will increment its + // install count. + // Otherwise the breakpoint will be processed as an initial + // breakpoint when the breakpoint tracking starts. + if (isBreakpointTargetTracked(bpTargetDMC)) { + // If the target breakpoint is thread specific, update thread filters + if (isThreadSpecific) { + setThreadSpecificBreakpoint(bpTargetDMC, plBpt, miBpt); + } + bm.breakpointAdded(plBpt); + } + } + // Make sure the platform breakpoint's parameters are synchronized + // with the target breakpoint. + Map map = fPendingModifications.get(bpTargetDMC); + if (map != null) { + MIBreakpoint mod = map.remove(Integer.valueOf(miBpt.getNumber())); + if (mod != null) { + targetBreakpointModified(bpTargetDMC, plBpt, mod); + } + } + else { + targetBreakpointModified(bpTargetDMC, plBpt, miBpt); + } + } + catch(CoreException e) { + GdbPlugin.log(getStatus()); + } + super.handleSuccess(); + } + }); + } + + public void targetBreakpointDeleted(final int id) { + MIBreakpoints breakpointsService = getBreakpointsService(); + final MIBreakpointsManager bm = getBreakpointsManager(); + if (breakpointsService == null || bm == null) + return; + final IBreakpointsTargetDMContext bpTargetDMC = breakpointsService.getBreakpointTargetContext(id); + final IContainerDMContext contDMC = DMContexts.getAncestorOfType(bpTargetDMC, IContainerDMContext.class); + if (contDMC == null) + return; + if (bpTargetDMC != null){ + final MIBreakpointDMContext bpDMC = + new MIBreakpointDMContext(breakpointsService, new IDMContext[] { bpTargetDMC }, id); + breakpointsService.getBreakpointDMData( + bpDMC, + new DataRequestMonitor(getExecutor(), null) { + @Override + @ConfinedToDsfExecutor( "fExecutor" ) + protected void handleSuccess() { + if (!(getData() instanceof MIBreakpointDMData)) + return; + MIBreakpointDMData data = (MIBreakpointDMData)getData(); + if (MIBreakpoints.CATCHPOINT.equals(data.getBreakpointType())) + return; + + IBreakpoint plBpt = bm.findPlatformBreakpoint(bpDMC); + if (plBpt instanceof ICBreakpoint) { + Set set = fDeletedTargetBreakpoints.get(bpTargetDMC); + if (set == null) { + set = new HashSet(); + fDeletedTargetBreakpoints.put(bpTargetDMC, set); + } + set.add(Integer.valueOf(id)); + + try { + int threadId = Integer.parseInt(data.getThreadId()); + if (threadId > 0) { + IDsfBreakpointExtension bpExtension = + (IDsfBreakpointExtension)((ICBreakpoint)plBpt).getExtension( + MIBreakpointsManager.GDB_DEBUG_MODEL_ID, ICBreakpointExtension.class); + IExecutionDMContext[] execDMCs = bpExtension.getThreadFilters(contDMC); + List list = new ArrayList(execDMCs.length); + for (IExecutionDMContext c : execDMCs) { + if (c instanceof IMIExecutionDMContext + && ((IMIExecutionDMContext)c).getThreadId() != threadId) + list.add(c); + } + if (list.size() > 0) { + bpExtension.setThreadFilters(list.toArray(new IExecutionDMContext[list.size()])); + } + else { + bm.uninstallBreakpoint(bpTargetDMC, (ICBreakpoint)plBpt, new RequestMonitor(getExecutor(), null)); + } + } + else { + bm.uninstallBreakpoint(bpTargetDMC, (ICBreakpoint)plBpt, new RequestMonitor(getExecutor(), null)); + } + } + catch(CoreException e) { + GdbPlugin.log(e.getStatus()); + } + catch(NumberFormatException e) { + GdbPlugin.log(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Invalid thread id")); //$NON-NLS-1$ + } + } + } + }); + + } + } + + public void targetBreakpointModified(final MIBreakpoint miBpt) { + if (isCatchpoint(miBpt)) + return; + ICommandControlService commandControl = getCommandControl(); + MIBreakpoints breakpointsService = getBreakpointsService(); + final MIBreakpointsManager bm = getBreakpointsManager(); + if (commandControl != null && breakpointsService != null && bm != null) { + final IBreakpointsTargetDMContext bpTargetDMC = getBreakpointsTargetContext(commandControl, miBpt); + if (bpTargetDMC == null) + return; + final Map contextBreakpoints = breakpointsService.getBreakpointMap(bpTargetDMC); + if (contextBreakpoints == null) + return; + IBreakpoint b = bm.findPlatformBreakpoint( + new MIBreakpointDMContext(breakpointsService, new IDMContext[] { bpTargetDMC }, miBpt.getNumber())); + if (!(b instanceof ICBreakpoint)) { + // Platform breakpoint hasn't been created yet. Store the latest + // modification data, it will be picked up later. + Map map = fPendingModifications.get(bpTargetDMC); + if (map == null) { + map = new HashMap(); + fPendingModifications.put(bpTargetDMC, map); + } + map.put(Integer.valueOf(miBpt.getNumber()), miBpt); + } + else { + ICBreakpoint plBpt = (ICBreakpoint)b; + targetBreakpointModified(bpTargetDMC, plBpt, miBpt); + } + } + } + + private void targetBreakpointModified( + IBreakpointsTargetDMContext bpTargetDMC, + ICBreakpoint plBpt, + MIBreakpoint miBpt) { + Map contextBreakpoints = getBreakpointsService().getBreakpointMap(bpTargetDMC); + MIBreakpointDMData oldData = contextBreakpoints.get(Integer.valueOf(miBpt.getNumber())); + contextBreakpoints.put(Integer.valueOf(miBpt.getNumber()), new MIBreakpointDMData(miBpt)); + try { + if (plBpt.isEnabled() != miBpt.isEnabled()) { + plBpt.setEnabled(miBpt.isEnabled()); + } + if (!plBpt.getCondition().equals(miBpt.getCondition())) { + plBpt.setCondition(miBpt.getCondition()); + } + if (plBpt.getIgnoreCount() != miBpt.getIgnoreCount()) { + plBpt.setIgnoreCount(miBpt.getIgnoreCount()); + } + if (oldData.isPending() != miBpt.isPending()) { + if (miBpt.isPending()) + plBpt.decrementInstallCount(); + else + plBpt.incrementInstallCount(); + } + if (plBpt instanceof ICTracepoint && miBpt.isTracepoint()) { + ICTracepoint plTpt = (ICTracepoint)plBpt; + if (plTpt.getPassCount() != miBpt.getPassCount()) { + // GDB (up to 7.5) doesn't emit notification when the pass count is modified. + plTpt.setPassCount(miBpt.getPassCount()); + } + + if (!miBpt.getCommands().equals(plBpt.getMarker().getAttribute(BreakpointActionManager.BREAKPOINT_ACTION_ATTRIBUTE))) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + String[] commands = miBpt.getCommands().split(TracepointActionManager.TRACEPOINT_ACTION_DELIMITER); + for (ITracepointAction action : getActionsFromCommands(commands)) { + if (first) + first = false; + else + sb.append(TracepointActionManager.TRACEPOINT_ACTION_DELIMITER); + sb.append(action.getName()); + } + // Target breakpoints and platform breakpoints use the same format + // to store trace commands. This format is different than the format + // used by GDB. We need to switch to the platform format to avoid unnecessary + // modifications of target breakpoints. + miBpt.setCommands(sb.toString()); + plBpt.getMarker().setAttribute( + BreakpointActionManager.BREAKPOINT_ACTION_ATTRIBUTE, sb.toString()); + } + } + } + catch(CoreException e) { + contextBreakpoints.put(Integer.valueOf(miBpt.getNumber()), oldData); + GdbPlugin.log(e.getStatus()); + } + } + + private void setThreadSpecificBreakpoint( + IBreakpointsTargetDMContext bpTargetDMC, + final ICBreakpoint plBpt, + MIBreakpoint miBpt) { + + try { + IContainerDMContext contDMC = DMContexts.getAncestorOfType(bpTargetDMC, IContainerDMContext.class); + if (contDMC == null) { + return; + } + IProcessDMContext procDmc = + DMContexts.getAncestorOfType(contDMC, IProcessDMContext.class); + if (procDmc == null) { + return; + } + IMIProcesses processes = getServicesTracker().getService(IMIProcesses.class); + if (processes == null) { + return; + } + IDsfBreakpointExtension bpExtension = (IDsfBreakpointExtension)plBpt.getExtension( + MIBreakpointsManager.GDB_DEBUG_MODEL_ID, ICBreakpointExtension.class); + IExecutionDMContext[] execDMCs = bpExtension.getThreadFilters(contDMC); + if (execDMCs == null) { + execDMCs = new IExecutionDMContext[0]; + } + int threadId = Integer.parseInt(miBpt.getThreadId()); + for (IExecutionDMContext execDMC : execDMCs) { + if (execDMC instanceof IMIExecutionDMContext + && ((IMIExecutionDMContext)execDMC).getThreadId() == threadId) { + // The platform breakpoint is already restricted to the given thread. + return; + } + } + IExecutionDMContext[] newExecDMCs = new IExecutionDMContext[execDMCs.length + 1]; + System.arraycopy(execDMCs, 0, newExecDMCs, 0, execDMCs.length); + newExecDMCs[execDMCs.length] = processes.createExecutionContext( + contDMC, + processes.createThreadContext(procDmc, miBpt.getThreadId()), + miBpt.getThreadId()); + bpExtension.setThreadFilters(newExecDMCs); + } + catch(NumberFormatException e) { + GdbPlugin.log(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Invalid thread id")); //$NON-NLS-1$ + } + catch(CoreException e) { + GdbPlugin.log(e); + } + } + + private ICBreakpoint getPlatformBreakpoint(MIBreakpoint miBpt, String fileName) { + for (IBreakpoint b : DebugPlugin.getDefault().getBreakpointManager().getBreakpoints()) { + if (b instanceof ICTracepoint + && miBpt.isTracepoint() + && isPlatformTracepoint((ICTracepoint)b, miBpt, fileName)) { + return (ICBreakpoint)b; + } + if (b instanceof ICWatchpoint + && miBpt.isWatchpoint() + && isPlatformWatchpoint((ICWatchpoint)b, miBpt)) { + return (ICBreakpoint)b; + } + if (b instanceof ICLineBreakpoint + && !miBpt.isWatchpoint() + && !isCatchpoint(miBpt) + && !miBpt.isTracepoint() + && isPlatformLineBreakpoint((ICLineBreakpoint)b, miBpt, fileName)) { + return (ICBreakpoint)b; + } + } + return null; + } + + private ICBreakpoint createPlatformBreakpoint(String fileName, MIBreakpoint miBpt) throws CoreException { + if (miBpt.isWatchpoint()) { + return createPlatformWatchpoint(fileName, miBpt); + } + else if (miBpt.isTracepoint()) { + return createPlatformTracepoint(fileName, miBpt); + } + else { + return createPlatformLocationBreakpoint(fileName, miBpt); + } + } + + private ICBreakpoint createPlatformLocationBreakpoint(String fileName, MIBreakpoint miBpt) throws CoreException { + if (isAddressBreakpoint(miBpt)) { + return createPlatformAddressBreakpoint(fileName, miBpt); + } + else if (isFunctionBreakpoint(miBpt)) { + return createPlatformFunctionBreakpoint(fileName, miBpt); + } + else { + return createPlatformLineBreakpoint(fileName, miBpt); + } + } + + private ICBreakpoint createPlatformAddressBreakpoint(String fileName, MIBreakpoint miBpt) throws CoreException { + IResource resource = getResource(fileName); + + int type = 0; + if (miBpt.isTemporary()) + type |= ICBreakpointType.TEMPORARY; + if (miBpt.isHardware()) + type |= ICBreakpointType.HARDWARE; + + try { + return CDIDebugModel.createAddressBreakpoint( + null, + null, + resource, + type, + getPlatformAddress(miBpt.getAddress()), + miBpt.isEnabled(), + miBpt.getIgnoreCount(), + miBpt.getCondition(), + true); + } + catch(NumberFormatException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.getUniqueIdentifier(), + String.format("Invalid breakpoint addres: %s", miBpt.getAddress()))); //$NON-NLS-1$ + } + } + + private ICBreakpoint createPlatformFunctionTracepoint(String fileName, MIBreakpoint miBpt) throws CoreException { + IResource resource = getResource(fileName); + + int type = 0; + if (miBpt.isTemporary()) + type |= ICBreakpointType.TEMPORARY; + if (miBpt.isHardware()) + type |= ICBreakpointType.HARDWARE; + + return CDIDebugModel.createFunctionTracepoint( + fileName, + resource, + type, + getFunctionName(miBpt), + -1, + -1, + getLineNumber(miBpt), + miBpt.isEnabled(), + miBpt.getIgnoreCount(), + miBpt.getCondition(), + true); + } + + private ICBreakpoint createPlatformLineTracepoint(String fileName, MIBreakpoint miBpt) throws CoreException { + IResource resource = getResource(fileName); + + int type = 0; + if (miBpt.isTemporary()) + type |= ICBreakpointType.TEMPORARY; + if (miBpt.isHardware()) + type |= ICBreakpointType.HARDWARE; + + return CDIDebugModel.createLineTracepoint( + fileName, + resource, + type, + getLineNumber(miBpt), + miBpt.isEnabled(), + miBpt.getIgnoreCount(), + miBpt.getCondition(), + true); + } + + private ICBreakpoint createPlatformTracepoint(String fileName, MIBreakpoint miBpt) throws CoreException { + if (isAddressBreakpoint(miBpt)) { + return createPlatformAddressTracepoint(fileName, miBpt); + } + else if (isFunctionBreakpoint(miBpt)) { + return createPlatformFunctionTracepoint(fileName, miBpt); + } + else { + return createPlatformLineTracepoint(fileName, miBpt); + } + } + + private ICBreakpoint createPlatformAddressTracepoint(String fileName, MIBreakpoint miBpt) throws CoreException { + IResource resource = getResource(fileName); + + int type = 0; + if (miBpt.isTemporary()) + type |= ICBreakpointType.TEMPORARY; + if (miBpt.isHardware()) + type |= ICBreakpointType.HARDWARE; + + try { + return CDIDebugModel.createAddressTracepoint( + null, + null, + resource, + type, + getLineNumber(miBpt), + getPlatformAddress(miBpt.getAddress()), + miBpt.isEnabled(), + miBpt.getIgnoreCount(), + miBpt.getCondition(), + true); + } + catch(NumberFormatException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.getUniqueIdentifier(), + String.format("Invalid breakpoint addres: %s", miBpt.getAddress()))); //$NON-NLS-1$ + } + } + + private ICBreakpoint createPlatformFunctionBreakpoint(String fileName, MIBreakpoint miBpt) throws CoreException { + IResource resource = getResource(fileName); + + int type = 0; + if (miBpt.isTemporary()) + type |= ICBreakpointType.TEMPORARY; + if (miBpt.isHardware()) + type |= ICBreakpointType.HARDWARE; + + return CDIDebugModel.createFunctionBreakpoint( + fileName, + resource, + type, + getFunctionName(miBpt), + -1, + -1, + getLineNumber(miBpt), + miBpt.isEnabled(), + miBpt.getIgnoreCount(), + miBpt.getCondition(), + true); + } + + private ICBreakpoint createPlatformLineBreakpoint(String fileName, MIBreakpoint miBpt) throws CoreException { + IResource resource = getResource(fileName); + + int type = 0; + if (miBpt.isTemporary()) + type |= ICBreakpointType.TEMPORARY; + if (miBpt.isHardware()) + type |= ICBreakpointType.HARDWARE; + + return CDIDebugModel.createLineBreakpoint( + fileName, + resource, + type, + getLineNumber(miBpt), + miBpt.isEnabled(), + miBpt.getIgnoreCount(), + miBpt.getCondition(), + true); + } + + private ICBreakpoint createPlatformWatchpoint(String fileName, MIBreakpoint miBpt) throws CoreException { + IResource resource = getResource(fileName); + + int type = 0; + if (miBpt.isTemporary()) + type |= ICBreakpointType.TEMPORARY; + if (miBpt.isHardware()) + type |= ICBreakpointType.HARDWARE; + + return CDIDebugModel.createWatchpoint( + fileName, + resource, + type, + miBpt.isAccessWatchpoint() || miBpt.isWriteWatchpoint(), + miBpt.isAccessWatchpoint() || miBpt.isReadWatchpoint(), + miBpt.getExpression(), + miBpt.isEnabled(), + miBpt.getIgnoreCount(), + miBpt.getCondition(), + true); + } + + private IBreakpointsTargetDMContext getBreakpointsTargetContext(ICommandControlService commandControl, MIBreakpoint miBpt) { + IMIProcesses processes = getServicesTracker().getService(IMIProcesses.class); + if (processes == null) { + return null; + } + String threadId = (miBpt != null) ? miBpt.getThreadId() : null; + IContainerDMContext contContext = processes.createContainerContextFromThreadId(commandControl.getContext(), threadId); + if (contContext == null) { + return null; + } + return DMContexts.getAncestorOfType(contContext, IBreakpointsTargetDMContext.class); + } + + public MIBreakpoint getTargetBreakpoint(IBreakpointsTargetDMContext context, Map attributes) { + Map map = fCreatedTargetBreakpoints.get(context); + if (map == null) + return null; + String type = (String)attributes.get(MIBreakpoints.BREAKPOINT_TYPE); + if (MIBreakpoints.BREAKPOINT.equals(type)) { + return getTargetLineBreakpoint( + map.values(), + (String)attributes.get(MIBreakpoints.FILE_NAME), + (Integer)attributes.get(MIBreakpoints.LINE_NUMBER), + (String)attributes.get(MIBreakpoints.FUNCTION), + (String)attributes.get(MIBreakpoints.ADDRESS), + (Boolean)attributes.get(MIBreakpointDMData.IS_HARDWARE), + (Boolean)attributes.get(MIBreakpointDMData.IS_TEMPORARY)); + + } + else if (MIBreakpoints.TRACEPOINT.equals(type)) { + return getTargetTracepoint( + map.values(), + (String)attributes.get(MIBreakpoints.FILE_NAME), + (Integer)attributes.get(MIBreakpoints.LINE_NUMBER), + (String)attributes.get(MIBreakpoints.FUNCTION), + (String)attributes.get(MIBreakpoints.ADDRESS), + (Boolean)attributes.get(MIBreakpointDMData.IS_HARDWARE), + (Boolean)attributes.get(MIBreakpointDMData.IS_TEMPORARY)); + } + else if (MIBreakpoints.WATCHPOINT.equals(type)) { + return getTargetWatchpoint( + map.values(), + (String)attributes.get(MIBreakpoints.EXPRESSION), + (Boolean)attributes.get(MIBreakpoints.READ), + (Boolean)attributes.get(MIBreakpoints.WRITE), + (Boolean)attributes.get(MIBreakpointDMData.IS_HARDWARE), + (Boolean)attributes.get(MIBreakpointDMData.IS_TEMPORARY)); + + } + return null; + } + + private MIBreakpoint getTargetLineBreakpoint( + Collection targetBreakpoints, + String fileName, + Integer lineNumber, + String function, + String address, + Boolean isHardware, + Boolean isTemporary) { + for (MIBreakpoint miBpt : targetBreakpoints) { + if (!miBpt.isWatchpoint() && !isCatchpoint(miBpt) && !miBpt.isTracepoint() + && compareBreakpointAttributes( + miBpt, fileName, lineNumber, function, address, isHardware, isTemporary)) + return miBpt; + } + return null; + } + + private MIBreakpoint getTargetTracepoint( + Collection targetBreakpoints, + String fileName, + Integer lineNumber, + String function, + String address, + Boolean isHardware, + Boolean isTemporary) { + for (MIBreakpoint miBpt : targetBreakpoints) { + if (miBpt.isTracepoint() + && compareBreakpointAttributes( + miBpt, fileName, lineNumber, function, address, isHardware, isTemporary)) + return miBpt; + } + return null; + } + + private MIBreakpoint getTargetWatchpoint( + Collection targetBreakpoints, + String expression, + boolean readAccess, + boolean writeAccess, + Boolean isHardware, + Boolean isTemporary) { + for (MIBreakpoint miBpt : targetBreakpoints) { + if (!miBpt.isWatchpoint()) + continue; + if (expression == null || !expression.equals(miBpt.getExpression())) + continue; + if (readAccess && writeAccess && !miBpt.isAccessWatchpoint()) + continue; + if (readAccess && !writeAccess && !miBpt.isReadWatchpoint()) + continue; + if (!readAccess && writeAccess && !miBpt.isWriteWatchpoint()) + continue; + if (!compareBreakpointTypeAttributes(miBpt, isHardware, isTemporary)) + continue; + return miBpt; + } + return null; + } + + private boolean compareBreakpointAttributes( + MIBreakpoint miBpt, + String fileName, + Integer lineNumber, + String function, + String address, + Boolean isHardware, + Boolean isTemporary) { + return compareBreakpointLocationAttributes(miBpt, fileName, lineNumber, function, address) + && compareBreakpointTypeAttributes(miBpt, isHardware, isTemporary); + } + + private boolean compareBreakpointLocationAttributes( + MIBreakpoint miBpt, + String fileName, + Integer lineNumber, + String function, + String address) { + if (isFunctionBreakpoint(miBpt) && (function == null || !function.equals(getFunctionName(miBpt)))) + return false; + if (isAddressBreakpoint(miBpt) + && (address == null || !address.equals(getPlatformAddress(miBpt.getAddress()).toHexAddressString()))) + return false; + if (isLineBreakpoint(miBpt)) { + if (fileName == null || !fileName.equals(getFileName(miBpt))) + return false; + if (lineNumber == null || lineNumber.intValue() != getLineNumber(miBpt)) + return false; + } + return true; + } + + private boolean compareBreakpointTypeAttributes(MIBreakpoint miBpt, Boolean isHardware, Boolean isTemporary) { + if ((isHardware == null && miBpt.isHardware()) + || (isHardware != null && isHardware.booleanValue() != miBpt.isHardware())) + return false; + if ((isTemporary == null && miBpt.isTemporary()) + || (isTemporary != null && isTemporary.booleanValue() != miBpt.isTemporary())) + return false; + return true; + } + + public void removeCreatedTargetBreakpoint(IBreakpointsTargetDMContext context, MIBreakpoint miBpt) { + Map map = fCreatedTargetBreakpoints.get(context); + if (map != null) { + map.remove(Integer.valueOf(miBpt.getNumber())); + } + } + + private boolean isPlatformLineBreakpoint(ICLineBreakpoint plBpt, MIBreakpoint miBpt, String fileName) { + if (plBpt instanceof ICAddressBreakpoint) { + return isAddressBreakpoint(miBpt) ? + isPlatformAddressBreakpoint((ICAddressBreakpoint)plBpt, miBpt) : false; + } + if (plBpt instanceof ICFunctionBreakpoint) { + return isFunctionBreakpoint(miBpt) ? + isPlatformFunctionBreakpoint((ICFunctionBreakpoint)plBpt, miBpt) : false; + } + try { + if (fileName == null || !fileName.equals(plBpt.getSourceHandle())) + return false; + if (plBpt.getLineNumber() != getLineNumber(miBpt)) + return false; + return true; + } + catch(CoreException e) { + GdbPlugin.log(e.getStatus()); + } + return false; + } + + private boolean isPlatformFunctionBreakpoint(ICFunctionBreakpoint plBpt, MIBreakpoint miBpt) { + try { + return (plBpt.getFunction() != null && plBpt.getFunction().equals(getFunctionName(miBpt))); + } + catch(CoreException e) { + GdbPlugin.log(e.getStatus()); + } + return false; + } + + private boolean isPlatformAddressBreakpoint(ICAddressBreakpoint plBpt, MIBreakpoint miBpt) { + try { + return (plBpt.getAddress() != null + && plBpt.getAddress().equals(getPlatformAddress(miBpt.getAddress()).toHexAddressString())); + } + catch(CoreException e) { + GdbPlugin.log(e.getStatus()); + } + return false; + } + + private boolean isPlatformWatchpoint(ICWatchpoint plBpt, MIBreakpoint miBpt) { + try { + if (plBpt.getExpression() != null && plBpt.getExpression().equals(miBpt.getExpression()) ) { + if (miBpt.isAccessWatchpoint()) + return plBpt.isWriteType() && plBpt.isReadType(); + else if (miBpt.isReadWatchpoint()) + return !plBpt.isWriteType() && plBpt.isReadType(); + else if (miBpt.isWriteWatchpoint()) + return plBpt.isWriteType() && !plBpt.isReadType(); + } + } + catch(CoreException e) { + GdbPlugin.log(e.getStatus()); + } + return false; + } + + private boolean isPlatformTracepoint(ICTracepoint plBpt, MIBreakpoint miBpt, String fileName) { + return isPlatformLineBreakpoint(plBpt, miBpt, fileName); + } + + public boolean isTargetBreakpointDeleted(IBreakpointsTargetDMContext context, int bpId, boolean remove) { + Set set = fDeletedTargetBreakpoints.get(context); + if (set != null ) + return (remove) ? set.remove(Integer.valueOf(bpId)) : set.contains(Integer.valueOf(bpId)); + return false; + } + + /** + * Returns the list of tracepoint actions generated from the given command string. + * If the corresponding action for a command doesn't exist in TracepointActionManager + * the new action is created and added. + * + * @param commands list of gdb tracepoint commands separated by TracepointActionManager.TRACEPOINT_ACTION_DELIMITER + */ + private ITracepointAction[] getActionsFromCommands(String[] commands) { + List list = new ArrayList(); + TracepointActionManager tam = TracepointActionManager.getInstance(); + WhileSteppingAction whileStepping = null; + List subActions = null; + for (String command : commands) { + // Check if an action for this command exists + boolean found = false; + for (ITracepointAction action :tam.getActions()) { + if (command.equals(action.getSummary())) { + if (whileStepping == null || subActions == null) + list.add(action); + else + subActions.add(action); + found = true; + break; + } + } + if (!found) { + // Create a new action if an action for this command doesn't exists + ITracepointAction action = null; + if (command.startsWith(TC_COLLECT)) + action = createCollectAction(command.substring(TC_COLLECT.length())); + else if (command.startsWith(TC_TEVAL)) + action = createEvaluateAction(command.substring(TC_TEVAL.length())); + else if (command.startsWith(TC_WHILE_STEPPING)) { + whileStepping = createWhileSteppingAction(command.substring(TC_WHILE_STEPPING.length())); + if (whileStepping != null) + subActions = new ArrayList(); + } + else if (command.equals(TC_END)) { + if (whileStepping == null || subActions == null) + continue; + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (ITracepointAction a : subActions) { + if (first) + first = false; + else + sb.append(','); + sb.append(a.getName()); + } + whileStepping.setSubActionsNames(sb.toString()); + whileStepping.setSubActionsContent(sb.toString()); + action = whileStepping; + // Search for existing action for this 'while-stepping' command + for (ITracepointAction a :tam.getActions()) { + if (whileStepping.getSummary().equals(a.getSummary())) { + action = a; + found = true; + break; + } + } + whileStepping = null; + subActions.clear(); + subActions = null; + } + if (action != null) { + if (!found) + TracepointActionManager.getInstance().addAction(action); + if (whileStepping == null || subActions == null) { + list.add(action); + } + else { + subActions.add(action); + } + } + } + TracepointActionManager.getInstance().saveActionData(); + } + return list.toArray(new ITracepointAction[list.size()]); + } + + private CollectAction createCollectAction(String collectStr) { + CollectAction action = new CollectAction(); + action.setName(TracepointActionManager.getInstance().makeUniqueActionName(action.getDefaultName())); + action.setCollectString(collectStr); + return action; + } + + private EvaluateAction createEvaluateAction(String evalStr) { + EvaluateAction action = new EvaluateAction(); + action.setName(TracepointActionManager.getInstance().makeUniqueActionName(action.getDefaultName())); + action.setEvalString(evalStr); + return action; + } + + private WhileSteppingAction createWhileSteppingAction(String str) { + WhileSteppingAction action = new WhileSteppingAction(); + action.setName(TracepointActionManager.getInstance().makeUniqueActionName(action.getDefaultName())); + try { + action.setStepCount(Integer.parseInt(str.trim())); + } + catch(NumberFormatException e) { + return null; + } + return action; + } + + protected void getSource( + IBreakpointsTargetDMContext bpTargetDMC, + final String debuggerPath, + final DataRequestMonitor rm) { + + ISourceLookup sourceLookup = getServicesTracker().getService(ISourceLookup.class); + if (sourceLookup == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Source lookup service is not available")); //$NON-NLS-1$ + rm.done(); + return; + } + + ISourceLookupDMContext srcDmc = DMContexts.getAncestorOfType(bpTargetDMC, ISourceLookupDMContext.class); + if (srcDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "No source lookup context")); //$NON-NLS-1$ + rm.done(); + return; + } + + if (debuggerPath == null || debuggerPath.isEmpty()) { + rm.done(); + return; + } + + sourceLookup.getSource( + srcDmc, + debuggerPath, + new DataRequestMonitor(getExecutor(), rm) { + @Override + @ConfinedToDsfExecutor("fExecutor") + protected void handleCompleted() { + String fileName = null; + if (isSuccess()) { + if (getData() instanceof IFile) { + fileName = ((IFile)getData()).getLocation().toOSString(); + } + else if (getData() instanceof File) { + fileName = ((File)getData()).getAbsolutePath(); + } + else if (getData() instanceof ITranslationUnit) { + IPath location = ((ITranslationUnit)getData()).getLocation(); + if (location != null) + fileName = location.toOSString(); + } + else if (getData() instanceof LocalFileStorage) { + fileName = ((LocalFileStorage)getData()).getFile().getAbsolutePath(); + } + } + rm.setData((fileName != null && !fileName.isEmpty()) ? fileName : debuggerPath); + rm.done(); + } + }); + } + + private boolean isFunctionBreakpoint(MIBreakpoint miBpt) { + String origFunction = getFunctionFromOriginalLocation(miBpt.getOriginalLocation()); + if (miBpt.getFunction().isEmpty()) { + return !origFunction.isEmpty(); + } + String function = miBpt.getFunction(); + // For C++ the function name for "break x" is reported as "x()". + // To compare it to the name retrieved from the original location + // we need to remove "()". + int index = function.indexOf('('); + if (index > 0 && origFunction.indexOf('(') == -1) { + return function.substring(0, index).equals(origFunction); + } + return function.equals(origFunction); + } + + private boolean isAddressBreakpoint(MIBreakpoint miBpt) { + return miBpt.getOriginalLocation().startsWith("*"); //$NON-NLS-1$ + } + + private boolean isLineBreakpoint(MIBreakpoint miBpt) { + return !isFunctionBreakpoint(miBpt) && !isAddressBreakpoint(miBpt); + } + + private IAddress getPlatformAddress(String miAddress) { + int radix = 10; + if (miAddress.startsWith("0x")) { //$NON-NLS-1$ + radix = 16; + miAddress = miAddress.substring(2); + } + return new Addr64(new BigInteger(miAddress, radix)); + } + + private boolean isBreakpointTargetTracked(IBreakpointsTargetDMContext btTargetDMC) { + return fTrackedTargets.contains(btTargetDMC); + } + + private String getFileName(MIBreakpoint miBpt) { + String fileName = (miBpt.getFullName() != null && !miBpt.getFullName().isEmpty()) ? + miBpt.getFullName() : miBpt.getFile(); + if (fileName != null && !fileName.isEmpty()) + return fileName; + // When a breakpoint is set from the console on an invalid file both + // 'file' and 'fullname' attributes are not available, we need to parse + // the 'original-location' attribute to retrieve the file name. + String origLocation = miBpt.getOriginalLocation(); + if (origLocation.isEmpty()) { + // Shouldn't happen + GdbPlugin.log(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Invalid 'original-location' attribute")); //$NON-NLS-1$ + return ""; //$NON-NLS-1$ + } + if (origLocation.startsWith("*")) //$NON-NLS-1$ + // Address breakpoint + return ""; //$NON-NLS-1$ + int index = origLocation.lastIndexOf(':'); + return (index > 0) ? origLocation.substring(0, index) : ""; //$NON-NLS-1$ + } + + private int getLineNumber(MIBreakpoint miBpt) { + int lineNumber = miBpt.getLine(); + if (lineNumber != -1) + return lineNumber; + // When a breakpoint is set from the console on an invalid file + // the 'line' attributes is not available, we need to parse + // the 'original-location' attribute to retrieve the line number. + String origLocation = miBpt.getOriginalLocation(); + if (origLocation.isEmpty()) { + // Shouldn't happen + GdbPlugin.log(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Invalid 'original-location' attribute")); //$NON-NLS-1$ + return -1; + } + if (origLocation.startsWith("*")) //$NON-NLS-1$ + // Address breakpoint + return -1; + int index = origLocation.lastIndexOf(':'); + if (index > 0 && origLocation.length() > index + 1) { + try { + return Integer.valueOf(origLocation.substring(index + 1, origLocation.length())).intValue(); + } + catch(NumberFormatException e) { + // not a line breakpoint + } + } + return -1; + } + + private String getFunctionName(MIBreakpoint miBpt) { + if (miBpt.getFunction() != null && !miBpt.getFunction().isEmpty()) + return miBpt.getFunction(); + // When a function breakpoint is set from the console, the symbol associated with + // the function may not be known to GDB. In this case the 'function' attribute is + // not available, we need to parse the 'original-location' attribute to retrieve + // the function name. + return getFunctionFromOriginalLocation(miBpt.getOriginalLocation()); + } + + private IResource getResource(String fileName) { + IResource resource = null; + if (fileName == null || fileName.isEmpty()) + resource = ResourcesPlugin.getWorkspace().getRoot(); + else { + IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI( + URI.create(String.format("file:/%s", fileName))); //$NON-NLS-1$ + if (files.length > 0) { + resource = files[0]; + } + else { + resource = ResourcesPlugin.getWorkspace().getRoot(); + } + } + return resource; + } + + @DsfServiceEventHandler + public void eventDispatched(IExitedDMEvent e) { + if (e.getDMContext() instanceof IContainerDMContext) { + IBreakpointsTargetDMContext bpTargetDMContext = + DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class); + if (bpTargetDMContext != null) { + Map createdBreakpoints = fCreatedTargetBreakpoints.remove(bpTargetDMContext); + if (createdBreakpoints != null) + createdBreakpoints.clear(); + Map modifications = fPendingModifications.remove(bpTargetDMContext); + if (modifications != null) + modifications.clear(); + Set deletedBreakpoints = fDeletedTargetBreakpoints.remove(bpTargetDMContext); + if (deletedBreakpoints != null) + deletedBreakpoints.clear(); + } + } + } + + private String getFunctionFromOriginalLocation(String origLocation) { + if (origLocation.isEmpty()) { + // Shouldn't happen + GdbPlugin.log(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Invalid 'original-location' attribute")); //$NON-NLS-1$ + return ""; //$NON-NLS-1$ + } + if (origLocation.startsWith("*")) //$NON-NLS-1$ + // Address breakpoint + return ""; //$NON-NLS-1$ + int index = origLocation.lastIndexOf(':'); + String function = (index >= 0) ? origLocation.substring(index + 1) : origLocation; + try { + Integer.valueOf(function); + // Line breakpoint + return ""; //$NON-NLS-1$ + } + catch(NumberFormatException e) { + // possible function breakpoint + } + return function; + } + + protected boolean isCatchpoint(MIBreakpoint miBpt) { + // Since we are using the CLI 'catch' command to set catchpoints GDB will emit + // the 'breakpoint-created' notification even if the catchpoint is set from UI. + // In case of 'catch' and 'throw' events the value of the 'type' attribute in + // the breakpoint notification's data is 'breakpoint' instead of 'catchpoint'. + // In this cases to identify the correct type we need to check the content of + // the 'what' attribute. + return (miBpt.isCatchpoint() || + (!miBpt.isWatchpoint() && + (CE_EXCEPTION_CATCH.equals(miBpt.getExpression()) || + CE_EXCEPTION_THROW.equals(miBpt.getExpression())))); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIBreakpoint.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIBreakpoint.java index ad25af95923..753b1e1ceb6 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIBreakpoint.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIBreakpoint.java @@ -81,7 +81,8 @@ public class MIBreakpoint { String threadId = "0"; //$NON-NLS-1$ int ignore = 0; String commands = ""; //$NON-NLS-1$ - + String originalLocation = ""; //$NON-NLS-1$ + // For tracepoints int passcount = 0; @@ -145,6 +146,7 @@ public class MIBreakpoint { isCatchpoint = other.isCatchpoint; catchpointType = other.catchpointType; pending = other.pending; + originalLocation = other.originalLocation; if (other.groupIds != null) { groupIds = Arrays.copyOf(other.groupIds, other.groupIds.length); } @@ -292,6 +294,13 @@ public class MIBreakpoint { return exp; } + /** + * @since 4.2 + */ + public String getOriginalLocation() { + return originalLocation; + } + /** * If isCatchpoint is true, then this indicates the type of catchpoint * (event), as reported by gdb in its response to the CLI catch command. @@ -487,6 +496,9 @@ public class MIBreakpoint { type.startsWith("fast tracepoint")) { //$NON-NLS-1$ isTpt = true; } + if (type.startsWith("catchpoint")) { //$NON-NLS-1$ + isCatchpoint = true; + } // type="breakpoint" // default ok. } else if (var.equals("disp")) { //$NON-NLS-1$ @@ -541,6 +553,8 @@ public class MIBreakpoint { if (value instanceof MIList) { parseGroups((MIList)value); } + } else if (var.equals("original-location")) { //$NON-NLS-1$ + originalLocation = str; } } }