13 * Ericsson - Added Action support |
13 * Ericsson - Added Action support |
14 *******************************************************************************/ |
14 *******************************************************************************/ |
15 |
15 |
16 package org.eclipse.cdt.dsf.mi.service; |
16 package org.eclipse.cdt.dsf.mi.service; |
17 |
17 |
18 import java.util.ArrayList; |
18 import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator; |
19 import java.util.HashMap; |
|
20 import java.util.HashSet; |
|
21 import java.util.Hashtable; |
|
22 import java.util.List; |
|
23 import java.util.Map; |
|
24 import java.util.Set; |
|
25 import java.util.Vector; |
|
26 import java.util.concurrent.RejectedExecutionException; |
|
27 |
|
28 import org.eclipse.cdt.debug.core.CDebugCorePlugin; |
|
29 import org.eclipse.cdt.debug.core.breakpointactions.BreakpointActionManager; |
|
30 import org.eclipse.cdt.debug.core.model.ICAddressBreakpoint; |
|
31 import org.eclipse.cdt.debug.core.model.ICBreakpoint; |
|
32 import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; |
|
33 import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; |
|
34 import org.eclipse.cdt.debug.core.model.ICWatchpoint; |
|
35 import org.eclipse.cdt.debug.internal.core.breakpoints.BreakpointProblems; |
|
36 import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; |
|
37 import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; |
|
38 import org.eclipse.cdt.dsf.concurrent.DsfRunnable; |
|
39 import org.eclipse.cdt.dsf.concurrent.RequestMonitor; |
|
40 import org.eclipse.cdt.dsf.concurrent.ThreadSafe; |
|
41 import org.eclipse.cdt.dsf.datamodel.DMContexts; |
|
42 import org.eclipse.cdt.dsf.datamodel.IDMContext; |
|
43 import org.eclipse.cdt.dsf.debug.service.IBreakpoints; |
|
44 import org.eclipse.cdt.dsf.debug.service.IDsfBreakpointExtension; |
|
45 import org.eclipse.cdt.dsf.debug.service.IRunControl; |
|
46 import org.eclipse.cdt.dsf.debug.service.ISourceLookup; |
|
47 import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext; |
|
48 import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; |
|
49 import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; |
|
50 import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; |
|
51 import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; |
|
52 import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; |
|
53 import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent; |
|
54 import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; |
|
55 import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.BreakpointAddedEvent; |
|
56 import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.BreakpointRemovedEvent; |
|
57 import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.BreakpointUpdatedEvent; |
|
58 import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext; |
|
59 import org.eclipse.cdt.dsf.mi.service.MIRunControl.SuspendedEvent; |
|
60 import org.eclipse.cdt.dsf.mi.service.breakpoint.actions.BreakpointActionAdapter; |
|
61 import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent; |
|
62 import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointScopeEvent; |
|
63 import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointTriggerEvent; |
|
64 import org.eclipse.cdt.dsf.service.AbstractDsfService; |
|
65 import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; |
|
66 import org.eclipse.cdt.dsf.service.DsfSession; |
19 import org.eclipse.cdt.dsf.service.DsfSession; |
67 import org.eclipse.core.resources.IMarker; |
|
68 import org.eclipse.core.resources.IMarkerDelta; |
|
69 import org.eclipse.core.resources.IResource; |
|
70 import org.eclipse.core.resources.IWorkspaceRunnable; |
|
71 import org.eclipse.core.resources.ResourcesPlugin; |
|
72 import org.eclipse.core.runtime.CoreException; |
|
73 import org.eclipse.core.runtime.IProgressMonitor; |
|
74 import org.eclipse.core.runtime.IStatus; |
|
75 import org.eclipse.core.runtime.Platform; |
|
76 import org.eclipse.core.runtime.Status; |
|
77 import org.eclipse.core.runtime.jobs.ISchedulingRule; |
|
78 import org.eclipse.core.runtime.jobs.Job; |
|
79 import org.eclipse.core.runtime.jobs.MultiRule; |
|
80 import org.eclipse.debug.core.DebugPlugin; |
|
81 import org.eclipse.debug.core.IBreakpointListener; |
|
82 import org.eclipse.debug.core.IBreakpointManager; |
|
83 import org.eclipse.debug.core.IBreakpointManagerListener; |
|
84 import org.eclipse.debug.core.model.IBreakpoint; |
|
85 import org.osgi.framework.BundleContext; |
|
86 |
20 |
87 /** |
21 /** |
88 * Breakpoint service interface. The breakpoint service tracks CDT breakpoint |
22 * Breakpoint service interface. The breakpoint service tracks CDT breakpoint |
89 * objects, and based on those, it manages breakpoints in the debugger back end. |
23 * objects, and based on those, it manages breakpoints in the debugger back end. |
90 * |
24 * |
91 * It relies on MIBreakpoints for the actual back-end interface. |
25 * It relies on MIBreakpoints for the actual back-end interface. |
92 */ |
26 */ |
93 public class MIBreakpointsManager extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener |
27 public class MIBreakpointsManager extends BreakpointsMediator |
94 { |
28 { |
95 // Note: Find a way to import this (careful of circular dependencies) |
|
96 public final static String GDB_DEBUG_MODEL_ID = "org.eclipse.cdt.dsf.gdb"; //$NON-NLS-1$ |
|
97 |
|
98 // Extra breakpoint attributes |
|
99 private static final String ATTR_DEBUGGER_PATH = GdbPlugin.PLUGIN_ID + ".debuggerPath"; //$NON-NLS-1$ |
|
100 private static final String ATTR_THREAD_FILTER = GdbPlugin.PLUGIN_ID + ".threadFilter"; //$NON-NLS-1$ |
|
101 private static final String ATTR_THREAD_ID = GdbPlugin.PLUGIN_ID + ".threadID"; //$NON-NLS-1$ |
|
102 |
|
103 // Services |
|
104 ICommandControl fConnection; |
|
105 IRunControl fRunControl; |
|
106 ISourceLookup fSourceLookup; |
|
107 IBreakpoints fBreakpoints; |
|
108 IBreakpointManager fBreakpointManager; // Platform breakpoint manager (not this!) |
|
109 BreakpointActionManager fBreakpointActionManager; |
|
110 |
|
111 /////////////////////////////////////////////////////////////////////////// |
|
112 // Breakpoints tracking |
|
113 /////////////////////////////////////////////////////////////////////////// |
|
114 |
|
115 private String fDebugModelId; |
|
116 |
|
117 // Holds the set of platform breakpoints with their corresponding back-end |
|
118 // breakpoint attributes, per context (i.e. each platform breakpoint is |
|
119 // replicated for each execution context). |
|
120 // - Context entry added/removed on start/stopTrackingBreakpoints() |
|
121 // - Augmented on breakpointAdded() |
|
122 // - Modified on breakpointChanged() |
|
123 // - Diminished on breakpointRemoved() |
|
124 private Map<IBreakpointsTargetDMContext, Map<ICBreakpoint, Map<String, Object>>> fPlatformBPs = |
|
125 new HashMap<IBreakpointsTargetDMContext, Map<ICBreakpoint, Map<String, Object>>>(); |
|
126 |
|
127 // Holds the set of target breakpoints, per execution context, and their |
|
128 // mapping to the corresponding platform breakpoint. In a given execution |
|
129 // context there can only be one platform breakpoint per target breakpoint. |
|
130 // Acts as a mapping from target (low-level) BP to the corresponding platform |
|
131 // (high-level) BP. |
|
132 // Updated when: |
|
133 // - We start/stop tracking an execution context |
|
134 // - A platform breakpoint is added/removed |
|
135 // - A thread filter is applied/removed |
|
136 private Map<IBreakpointsTargetDMContext, Map<IBreakpointDMContext, ICBreakpoint>> fTargetBPs = |
|
137 new HashMap<IBreakpointsTargetDMContext, Map<IBreakpointDMContext, ICBreakpoint>>(); |
|
138 |
|
139 // Holds the mapping from platform breakpoint to the corresponding target |
|
140 // breakpoint(s), per context. There can be multiple back-end BPs for a |
|
141 // single platform BP in the case of [1] multiple target contexts, and/or |
|
142 // [2] thread filtering. |
|
143 // Updated when: |
|
144 // - We start/stop tracking an execution context |
|
145 // - A platform breakpoint is added/removed |
|
146 // - A thread filter is applied/removed |
|
147 private Map<IBreakpointsTargetDMContext, Map<ICBreakpoint, Vector<IBreakpointDMContext>>> fBreakpointIDs = |
|
148 new HashMap<IBreakpointsTargetDMContext, Map<ICBreakpoint, Vector<IBreakpointDMContext>>>(); |
|
149 |
|
150 // Holds the mapping from platform breakpoint to the corresponding target |
|
151 // breakpoint threads, per context. |
|
152 // Updated when: |
|
153 // - We start/stop tracking an execution context |
|
154 // - A platform breakpoint is added/removed |
|
155 // - A thread filter is applied/removed |
|
156 private Map<IBreakpointsTargetDMContext, Map<ICBreakpoint, Set<String>>> fBreakpointThreads = |
|
157 new HashMap<IBreakpointsTargetDMContext, Map<ICBreakpoint, Set<String>>>(); |
|
158 |
|
159 // Due to the very asynchronous nature of DSF, a new breakpoint request can |
|
160 // pop up at any time before an ongoing one is completed. The following set |
|
161 // is used to store requests until the ongoing operation completes. |
|
162 private Set<IBreakpoint> fPendingRequests = new HashSet<IBreakpoint>(); |
|
163 private Set<IBreakpoint> fPendingBreakpoints = new HashSet<IBreakpoint>(); |
|
164 |
|
165 private Map<ICBreakpoint, IMarker> fBreakpointMarkerProblems = |
|
166 new HashMap<ICBreakpoint, IMarker>(); |
|
167 |
|
168 /////////////////////////////////////////////////////////////////////////// |
|
169 // String constants |
|
170 /////////////////////////////////////////////////////////////////////////// |
|
171 |
|
172 private static final String NULL_STRING = ""; //$NON-NLS-1$ |
|
173 |
|
174 static final String CONTEXT_ALREADY_INITIALIZED = "Context already initialized"; //$NON-NLS-1$ |
|
175 static final String INVALID_CONTEXT_TYPE = "Invalid context type"; //$NON-NLS-1$ |
|
176 static final String INVALID_CONTEXT = "Invalid context"; //$NON-NLS-1$ |
|
177 |
|
178 static final String UNABLE_TO_READ_BREAKPOINT = "Unable to read initial breakpoint attributes"; //$NON-NLS-1$ |
|
179 static final String BREAKPOINT_NOT_INSTALLED = "Breakpoints not installed for given context"; //$NON-NLS-1$ |
|
180 static final String BREAKPOINT_ALREADY_INSTALLED = "Breakpoint already installed"; //$NON-NLS-1$ |
|
181 static final String BREAKPOINT_ALREADY_REMOVED = "Breakpoint already removed"; //$NON-NLS-1$ |
|
182 |
|
183 static final String INVALID_BREAKPOINT = "Invalid breakpoint"; //$NON-NLS-1$ |
|
184 static final String UNKNOWN_BREAKPOINT = "Unknown breakpoint"; //$NON-NLS-1$ |
|
185 static final String INVALID_PARAMETER = "Invalid breakpoint parameter(s)"; //$NON-NLS-1$ |
|
186 |
|
187 static final String NO_DEBUGGER_PATH = "No debugger path for breakpoint"; //$NON-NLS-1$ |
|
188 static final String NO_MARKER_FOR_BREAKPOINT = "No marker associated with breakpoint"; //$NON-NLS-1$ |
|
189 |
|
190 /////////////////////////////////////////////////////////////////////////// |
|
191 // AbstractDsfService |
|
192 /////////////////////////////////////////////////////////////////////////// |
|
193 |
|
194 /** |
29 /** |
195 * The service constructor. |
30 * The service constructor. |
196 * Performs basic instantiation (method initialize() performs the real |
31 * Performs basic instantiation (method initialize() performs the real |
197 * service initialization asynchronously). |
32 * service initialization asynchronously). |
198 * |
33 * |
199 * @param session the debugging session |
34 * @param session the debugging session |
200 * @param debugModelId the debugging model |
35 * @param debugModelId the debugging model |
201 */ |
36 */ |
202 public MIBreakpointsManager(DsfSession session, String debugModelId) { |
37 public MIBreakpointsManager(DsfSession session, String debugModelId) { |
203 super(session); |
38 super(session, new MIBreakpointAttributeTranslator(session, debugModelId)); |
204 fDebugModelId = debugModelId; |
|
205 } |
39 } |
206 |
|
207 //------------------------------------------------------------------------- |
|
208 // initialize |
|
209 //------------------------------------------------------------------------- |
|
210 // - Collect references for the services we interact with |
|
211 // - Register to interesting events |
|
212 // - Obtain the list of platform breakpoints |
|
213 // - Register the service for interested parties |
|
214 //------------------------------------------------------------------------- |
|
215 |
|
216 /* (non-Javadoc) |
|
217 * @see org.eclipse.cdt.dsf.service.AbstractDsfService#initialize(org.eclipse.cdt.dsf.concurrent.RequestMonitor) |
|
218 */ |
|
219 @Override |
|
220 public void initialize(final RequestMonitor rm) { |
|
221 super.initialize( |
|
222 new RequestMonitor(getExecutor(), rm) { |
|
223 @Override |
|
224 protected void handleSuccess() { |
|
225 doInitialize(rm); |
|
226 }}); |
|
227 } |
|
228 |
|
229 /** |
|
230 * @param rm |
|
231 */ |
|
232 private void doInitialize(RequestMonitor rm) { |
|
233 |
|
234 // Get the required services references from central repository |
|
235 fConnection = getServicesTracker().getService(ICommandControl.class); |
|
236 fRunControl = getServicesTracker().getService(IRunControl.class); |
|
237 fSourceLookup = getServicesTracker().getService(ISourceLookup.class); |
|
238 fBreakpoints = getServicesTracker().getService(IBreakpoints.class); |
|
239 fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager(); |
|
240 fBreakpointActionManager = CDebugCorePlugin.getDefault().getBreakpointActionManager(); |
|
241 |
|
242 // Register to the useful events |
|
243 getSession().addServiceEventListener(this, null); |
|
244 fBreakpointManager.addBreakpointListener(this); |
|
245 fBreakpointManager.addBreakpointManagerListener(this); |
|
246 |
|
247 // And register this service |
|
248 register(new String[] { MIBreakpointsManager.class.getName() }, |
|
249 new Hashtable<String, String>()); |
|
250 rm.done(); |
|
251 } |
|
252 |
|
253 //------------------------------------------------------------------------- |
|
254 // shutdown |
|
255 //------------------------------------------------------------------------- |
|
256 // - Un-register the service |
|
257 // - Stop listening to events |
|
258 // - Remove the breakpoints installed by this service |
|
259 // |
|
260 // Since we are shutting down, there is no overwhelming need |
|
261 // to keep the maps coherent... |
|
262 //------------------------------------------------------------------------- |
|
263 |
|
264 /* (non-Javadoc) |
|
265 * @see org.eclipse.cdt.dsf.service.AbstractDsfService#shutdown(org.eclipse.cdt.dsf.concurrent.RequestMonitor) |
|
266 */ |
|
267 @Override |
|
268 public void shutdown(final RequestMonitor rm) { |
|
269 |
|
270 // Stop accepting requests and events |
|
271 unregister(); |
|
272 getSession().removeServiceEventListener(this); |
|
273 fBreakpointManager.removeBreakpointListener(this); |
|
274 fBreakpointManager.removeBreakpointManagerListener(this); |
|
275 |
|
276 // Cleanup the breakpoints that are still installed by the service. |
|
277 // Use a counting monitor which will call mom to complete the shutdown |
|
278 // after the breakpoints are un-installed (successfully or not). |
|
279 CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { |
|
280 @Override |
|
281 protected void handleCompleted() { |
|
282 MIBreakpointsManager.super.shutdown(rm); |
|
283 } |
|
284 }; |
|
285 |
|
286 List<IBreakpointsTargetDMContext> targetBPKeys = new ArrayList<IBreakpointsTargetDMContext>(fTargetBPs.size()); |
|
287 targetBPKeys.addAll(0, fTargetBPs.keySet()); |
|
288 for (IBreakpointsTargetDMContext dmc : targetBPKeys) { |
|
289 stopTrackingBreakpoints(dmc, countingRm); |
|
290 } |
|
291 countingRm.setDoneCount(targetBPKeys.size()); |
|
292 } |
|
293 |
|
294 //------------------------------------------------------------------------- |
|
295 // getBundleContext |
|
296 //------------------------------------------------------------------------- |
|
297 |
|
298 /* (non-Javadoc) |
|
299 * @see org.eclipse.cdt.dsf.service.AbstractDsfService#getBundleContext() |
|
300 */ |
|
301 @Override |
|
302 protected BundleContext getBundleContext() { |
|
303 return GdbPlugin.getBundleContext(); |
|
304 } |
|
305 |
|
306 /////////////////////////////////////////////////////////////////////////// |
|
307 // IBreakpointsManager |
|
308 /////////////////////////////////////////////////////////////////////////// |
|
309 |
|
310 //------------------------------------------------------------------------- |
|
311 // startTrackingBreakpoints |
|
312 //------------------------------------------------------------------------- |
|
313 // - Augment the maps with the new execution context |
|
314 // - Install the platform breakpoints on the selected target |
|
315 //------------------------------------------------------------------------- |
|
316 |
|
317 /** |
|
318 * Install and begin tracking breakpoints for given context. The service |
|
319 * will keep installing new breakpoints that appear in the IDE for this |
|
320 * context until {@link #uninstallBreakpoints(IDMContext)} is called for that |
|
321 * context. |
|
322 * @param dmc Context to start tracking breakpoints for. |
|
323 * @param rm Completion callback. |
|
324 */ |
|
325 public void startTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { |
|
326 |
|
327 // Validate the execution context |
|
328 if (dmc == null) { |
|
329 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_CONTEXT, null)); |
|
330 rm.done(); |
|
331 return; |
|
332 } |
|
333 |
|
334 // Make sure a mapping for this execution context does not already exist |
|
335 Map<ICBreakpoint,Map<String, Object>> platformBPs = fPlatformBPs.get(dmc); |
|
336 Map<ICBreakpoint, Vector<IBreakpointDMContext>> breakpointIDs = fBreakpointIDs.get(dmc); |
|
337 Map<IBreakpointDMContext, ICBreakpoint> targetIDs = fTargetBPs.get(dmc); |
|
338 Map<ICBreakpoint, Set<String>> threadIDs = fBreakpointThreads.get(dmc); |
|
339 if ((platformBPs != null) || (breakpointIDs != null) || (targetIDs != null) || (threadIDs != null)) { |
|
340 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, CONTEXT_ALREADY_INITIALIZED, null)); |
|
341 rm.done(); |
|
342 return; |
|
343 } |
|
344 |
|
345 // Create entries in the breakpoint tables for the new context. These entries should only |
|
346 // be removed when this service stops tracking breakpoints for the given context. |
|
347 fPlatformBPs.put(dmc, new HashMap<ICBreakpoint, Map<String, Object>>()); |
|
348 fBreakpointIDs.put(dmc, new HashMap<ICBreakpoint, Vector<IBreakpointDMContext>>()); |
|
349 fTargetBPs.put(dmc, new HashMap<IBreakpointDMContext, ICBreakpoint>()); |
|
350 fBreakpointThreads.put(dmc, new HashMap<ICBreakpoint, Set<String>>()); |
|
351 |
|
352 // Install the platform breakpoints (stored in fPlatformBPs) on the target. |
|
353 new Job("DSF BreakpointsManager: Install initial breakpoints on target") { //$NON-NLS-1$ |
|
354 @Override |
|
355 protected IStatus run(IProgressMonitor monitor) { |
|
356 // Submit the runnable to plant the breakpoints on dispatch thread. |
|
357 getExecutor().submit(new Runnable() { |
|
358 public void run() { |
|
359 installInitialBreakpoints(dmc, rm); |
|
360 } |
|
361 }); |
|
362 |
|
363 return Status.OK_STATUS; |
|
364 } |
|
365 }.schedule(); |
|
366 } |
|
367 |
|
368 /** |
|
369 * Installs the breakpoints that existed prior to the activation of this |
|
370 * execution context. |
|
371 * |
|
372 * @param dmc |
|
373 * @param initialPlatformBPs |
|
374 * @param rm |
|
375 */ |
|
376 private void installInitialBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) |
|
377 { |
|
378 // Retrieve the set of platform breakpoints for this context |
|
379 final Map<ICBreakpoint,Map<String, Object>> platformBPs = fPlatformBPs.get(dmc); |
|
380 if (platformBPs == null) { |
|
381 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); |
|
382 rm.done(); |
|
383 return; |
|
384 } |
|
385 |
|
386 // Read current breakpoints from platform and copy their augmented |
|
387 // attributes into the local reference map |
|
388 try { |
|
389 IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(fDebugModelId); |
|
390 for (IBreakpoint breakpoint : breakpoints) { |
|
391 if (supportsBreakpoint(breakpoint)) { |
|
392 @SuppressWarnings("unchecked") |
|
393 Map<String, Object> attributes = breakpoint.getMarker().getAttributes(); |
|
394 attributes.put(ATTR_DEBUGGER_PATH, NULL_STRING); |
|
395 attributes.put(ATTR_THREAD_FILTER, extractThreads(dmc, (ICBreakpoint) breakpoint)); |
|
396 attributes.put(ATTR_THREAD_ID, NULL_STRING); |
|
397 platformBPs.put((ICBreakpoint) breakpoint, attributes); |
|
398 } |
|
399 } |
|
400 } catch (CoreException e) { |
|
401 IStatus status = new Status( |
|
402 IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNABLE_TO_READ_BREAKPOINT, e); |
|
403 rm.setStatus(status); |
|
404 rm.done(); |
|
405 } |
|
406 |
|
407 // Install the individual breakpoints on the dispatcher thread |
|
408 // Requires a counting monitor to know when we are done |
|
409 final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm); |
|
410 countingRm.setDoneCount(platformBPs.size()); |
|
411 |
|
412 for (final ICBreakpoint breakpoint : platformBPs.keySet()) { |
|
413 final Map<String, Object> attributes = platformBPs.get(breakpoint); |
|
414 // Upon determining the debuggerPath, the breakpoint is installed |
|
415 determineDebuggerPath(dmc, attributes, new RequestMonitor(getExecutor(), countingRm) { |
|
416 @Override |
|
417 protected void handleSuccess() { |
|
418 // Install only if the breakpoint is enabled at startup (Bug261082) |
|
419 boolean bpEnabled = attributes.get(ICBreakpoint.ENABLED).equals(true) && fBreakpointManager.isEnabled(); |
|
420 if (bpEnabled) |
|
421 installBreakpoint(dmc, breakpoint, attributes, countingRm); |
|
422 else |
|
423 countingRm.done(); |
|
424 } |
|
425 }); |
|
426 } |
|
427 } |
|
428 |
|
429 //------------------------------------------------------------------------- |
|
430 // stopTrackingBreakpoints |
|
431 //------------------------------------------------------------------------- |
|
432 // - Remove the target breakpoints for the given execution context |
|
433 // - Update the maps |
|
434 //------------------------------------------------------------------------- |
|
435 |
|
436 /** |
|
437 * Uninstall and stop tracking breakpoints for the given context. |
|
438 * @param dmc Context to start tracking breakpoints for. |
|
439 * @param rm Completion callback. |
|
440 */ |
|
441 public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { |
|
442 |
|
443 // Validate the context |
|
444 if (dmc == null) { |
|
445 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); |
|
446 rm.done(); |
|
447 return; |
|
448 } |
|
449 |
|
450 // Retrieve the set of platform breakpoints for this context |
|
451 final Map<ICBreakpoint,Map<String, Object>> platformBPs = fPlatformBPs.get(dmc); |
|
452 if (platformBPs == null) { |
|
453 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); |
|
454 rm.done(); |
|
455 return; |
|
456 } |
|
457 |
|
458 // Un-install the individual breakpoints on the dispatcher thread |
|
459 // (requires a counting monitor to know when we are done). |
|
460 // On completion (success or failure), update the maps. |
|
461 final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { |
|
462 @Override |
|
463 protected void handleCompleted() { |
|
464 fPlatformBPs.remove(dmc); |
|
465 fBreakpointIDs.remove(dmc); |
|
466 fTargetBPs.remove(dmc); |
|
467 fBreakpointThreads.remove(dmc); |
|
468 rm.done(); |
|
469 } |
|
470 }; |
|
471 countingRm.setDoneCount(platformBPs.size()); |
|
472 |
|
473 for (final ICBreakpoint breakpoint : platformBPs.keySet()) { |
|
474 uninstallBreakpoint(dmc, breakpoint, |
|
475 new RequestMonitor(getExecutor(), countingRm) { |
|
476 @Override |
|
477 protected void handleCompleted() { |
|
478 countingRm.done(); |
|
479 } |
|
480 }); |
|
481 } |
|
482 } |
|
483 |
|
484 /////////////////////////////////////////////////////////////////////////// |
|
485 // Back-end interface functions |
|
486 /////////////////////////////////////////////////////////////////////////// |
|
487 |
|
488 //------------------------------------------------------------------------- |
|
489 // installBreakpoint |
|
490 //------------------------------------------------------------------------- |
|
491 |
|
492 /** |
|
493 * Install a platform breakpoint on the back-end. For a given context, a |
|
494 * platform breakpoint can resolve into multiple back-end breakpoints when |
|
495 * threads are taken into account. |
|
496 * |
|
497 * @param dmc |
|
498 * @param breakpoint |
|
499 * @param attributes |
|
500 * @param rm |
|
501 */ |
|
502 private void installBreakpoint(IBreakpointsTargetDMContext dmc, final ICBreakpoint breakpoint, |
|
503 final Map<String, Object> attributes, final RequestMonitor rm) |
|
504 { |
|
505 // Retrieve the breakpoint maps |
|
506 final Map<ICBreakpoint,Map<String,Object>> platformBPs = fPlatformBPs.get(dmc); |
|
507 assert platformBPs != null; |
|
508 |
|
509 final Map<ICBreakpoint, Vector<IBreakpointDMContext>> breakpointIDs = fBreakpointIDs.get(dmc); |
|
510 assert breakpointIDs != null; |
|
511 |
|
512 final Map<IBreakpointDMContext, ICBreakpoint> targetBPs = fTargetBPs.get(dmc); |
|
513 assert targetBPs != null; |
|
514 |
|
515 final Map<ICBreakpoint, Set<String>> threadsIDs = fBreakpointThreads.get(dmc); |
|
516 assert threadsIDs != null; |
|
517 |
|
518 // Minimal validation |
|
519 if (breakpointIDs.containsKey(breakpoint) || targetBPs.containsValue(breakpoint)) { |
|
520 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, BREAKPOINT_ALREADY_INSTALLED, null)); |
|
521 rm.done(); |
|
522 return; |
|
523 } |
|
524 |
|
525 // Ensure the breakpoint has a valid debugger source path |
|
526 if (breakpoint instanceof ICLineBreakpoint && !(breakpoint instanceof ICAddressBreakpoint)) { |
|
527 String debuggerPath = (String) attributes.get(ATTR_DEBUGGER_PATH); |
|
528 if (debuggerPath == null || debuggerPath == NULL_STRING) { |
|
529 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, NO_DEBUGGER_PATH, null)); |
|
530 rm.done(); |
|
531 return; |
|
532 } |
|
533 } |
|
534 |
|
535 // A back-end breakpoint needs to be installed for each specified thread |
|
536 // Note: This is a bit academic since [1] thread info is not kept by the |
|
537 // BreakpointManager (so it can not possibly be restored when a target is |
|
538 // started), and [2] the standard GUI doesn't allow to specify thread at |
|
539 // breakpoint creation. However, it is conceivable that an enhanced Editor |
|
540 // would permit it. |
|
541 final Set<String> threads = getThreads(attributes); |
|
542 |
|
543 // Update the breakpoint state when all back-end breakpoints have been installed |
|
544 final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), rm) { |
|
545 @Override |
|
546 protected void handleCompleted() { |
|
547 // Store the platform breakpoint |
|
548 platformBPs.put(breakpoint, attributes); |
|
549 rm.done(); |
|
550 } |
|
551 }; |
|
552 installRM.setDoneCount(threads.size()); |
|
553 |
|
554 // Install the back-end breakpoint(s) |
|
555 for (final String thread : threads) { |
|
556 DataRequestMonitor<IBreakpointDMContext> drm = |
|
557 new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), installRM) { |
|
558 @Override |
|
559 protected void handleSuccess() { |
|
560 // Add the new back-end breakpoint to the map |
|
561 Vector<IBreakpointDMContext> list = breakpointIDs.get(breakpoint); |
|
562 if (list == null) |
|
563 list = new Vector<IBreakpointDMContext>(); |
|
564 IBreakpointDMContext targetBP = getData(); |
|
565 list.add(targetBP); |
|
566 breakpointIDs.put(breakpoint, list); |
|
567 |
|
568 // Add the reverse mapping |
|
569 targetBPs.put(targetBP, breakpoint); |
|
570 |
|
571 // And update the corresponding thread list |
|
572 Set<String> thrds = threadsIDs.get(breakpoint); |
|
573 if (thrds == null) |
|
574 thrds = new HashSet<String>(); |
|
575 thrds.add(thread); |
|
576 threadsIDs.put(breakpoint, thrds); |
|
577 |
|
578 // Reset the thread (is it necessary?) |
|
579 attributes.put(ATTR_THREAD_ID, NULL_STRING); |
|
580 |
|
581 // Remove breakpoint problem marker (if any) |
|
582 removeBreakpointProblemMarker(breakpoint); |
|
583 |
|
584 // Finally, update the platform breakpoint |
|
585 try { |
|
586 breakpoint.incrementInstallCount(); |
|
587 } catch (CoreException e) { |
|
588 } |
|
589 installRM.done(); |
|
590 } |
|
591 |
|
592 @Override |
|
593 protected void handleError() { |
|
594 addBreakpointProblemMarker(breakpoint, "Breakpoint attribute problem: installation failed", IMarker.SEVERITY_WARNING); //$NON-NLS-1$ |
|
595 installRM.done(); |
|
596 } |
|
597 }; |
|
598 |
|
599 // Convert the breakpoint attributes for the back-end |
|
600 attributes.put(ATTR_THREAD_ID, thread); |
|
601 Map<String,Object> targetAttributes = convertToTargetBreakpoint(breakpoint, attributes); |
|
602 fBreakpoints.insertBreakpoint(dmc, targetAttributes, drm); |
|
603 } |
|
604 } |
|
605 |
|
606 private void addBreakpointProblemMarker(final ICBreakpoint breakpoint, final String description, final int severity) { |
|
607 |
|
608 new Job("Add Breakpoint Problem Marker") { //$NON-NLS-1$ |
|
609 @Override |
|
610 protected IStatus run(IProgressMonitor monitor) { |
|
611 |
|
612 if (breakpoint instanceof ICLineBreakpoint) { |
|
613 // If we have already have a problem marker on this breakpoint |
|
614 // we should remove it first. |
|
615 IMarker marker = fBreakpointMarkerProblems.remove(breakpoint); |
|
616 if (marker != null) { |
|
617 try { |
|
618 marker.delete(); |
|
619 } catch (CoreException e) { |
|
620 } |
|
621 } |
|
622 |
|
623 ICLineBreakpoint lineBreakpoint = (ICLineBreakpoint) breakpoint; |
|
624 try { |
|
625 // Locate the workspace resource via the breakpoint marker |
|
626 IMarker breakpoint_marker = lineBreakpoint.getMarker(); |
|
627 IResource resource = breakpoint_marker.getResource(); |
|
628 |
|
629 // Add a problem marker to the resource |
|
630 IMarker problem_marker = resource.createMarker(BreakpointProblems.BREAKPOINT_PROBLEM_MARKER_ID); |
|
631 int line_number = lineBreakpoint.getLineNumber(); |
|
632 problem_marker.setAttribute(IMarker.LOCATION, String.valueOf(line_number)); |
|
633 problem_marker.setAttribute(IMarker.MESSAGE, description); |
|
634 problem_marker.setAttribute(IMarker.SEVERITY, severity); |
|
635 problem_marker.setAttribute(IMarker.LINE_NUMBER, line_number); |
|
636 |
|
637 // And save the baby |
|
638 fBreakpointMarkerProblems.put(breakpoint, problem_marker); |
|
639 } catch (CoreException e) { |
|
640 } |
|
641 } |
|
642 return Status.OK_STATUS; |
|
643 } |
|
644 }.schedule(); |
|
645 } |
|
646 |
|
647 private void removeBreakpointProblemMarker(final ICBreakpoint breakpoint) { |
|
648 |
|
649 new Job("Remove Breakpoint Problem Marker") { //$NON-NLS-1$ |
|
650 @Override |
|
651 protected IStatus run(IProgressMonitor monitor) { |
|
652 |
|
653 IMarker marker = fBreakpointMarkerProblems.remove(breakpoint); |
|
654 if (marker != null) { |
|
655 try { |
|
656 marker.delete(); |
|
657 } catch (CoreException e) { |
|
658 } |
|
659 } |
|
660 |
|
661 return Status.OK_STATUS; |
|
662 } |
|
663 }.schedule(); |
|
664 } |
|
665 |
|
666 //------------------------------------------------------------------------- |
|
667 // uninstallBreakpoint |
|
668 //------------------------------------------------------------------------- |
|
669 |
|
670 /** |
|
671 * Un-install an individual breakpoint on the back-end. For one platform |
|
672 * breakpoint in a given execution context, there could be multiple |
|
673 * corresponding back-end breakpoints (one per thread). |
|
674 * |
|
675 * @param dmc |
|
676 * @param breakpoint |
|
677 * @param rm |
|
678 */ |
|
679 private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, |
|
680 final ICBreakpoint breakpoint, final RequestMonitor rm) |
|
681 { |
|
682 // Retrieve the breakpoint maps |
|
683 final Map<ICBreakpoint,Map<String,Object>> platformBPs = fPlatformBPs.get(dmc); |
|
684 assert platformBPs != null; |
|
685 |
|
686 final Map<ICBreakpoint, Vector<IBreakpointDMContext>> breakpointIDs = fBreakpointIDs.get(dmc); |
|
687 assert breakpointIDs != null; |
|
688 |
|
689 final Map<IBreakpointDMContext, ICBreakpoint> targetBPs = fTargetBPs.get(dmc); |
|
690 assert targetBPs != null; |
|
691 |
|
692 final Map<ICBreakpoint, Set<String>> threadsIDs = fBreakpointThreads.get(dmc); |
|
693 assert threadsIDs != null; |
|
694 |
|
695 // Remove breakpoint problem marker (if any) |
|
696 removeBreakpointProblemMarker(breakpoint); |
|
697 |
|
698 // Minimal validation |
|
699 if (!platformBPs.containsKey(breakpoint) || !breakpointIDs.containsKey(breakpoint) || !targetBPs.containsValue(breakpoint)) { |
|
700 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, BREAKPOINT_ALREADY_REMOVED, null)); |
|
701 rm.done(); |
|
702 return; |
|
703 } |
|
704 |
|
705 // Remove completion monitor |
|
706 // Upon completion, update the mappings |
|
707 CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) { |
|
708 @Override |
|
709 protected void handleSuccess() { |
|
710 // Update the mappings |
|
711 platformBPs.remove(breakpoint); |
|
712 threadsIDs.remove(breakpoint); |
|
713 |
|
714 Vector<IBreakpointDMContext> contexts = breakpointIDs.get(breakpoint); |
|
715 if (contexts != null) { |
|
716 for (IBreakpointDMContext context : contexts) |
|
717 targetBPs.remove(context); |
|
718 } |
|
719 |
|
720 breakpointIDs.get(breakpoint).clear(); |
|
721 breakpointIDs.remove(breakpoint); |
|
722 |
|
723 fPendingRequests.remove(breakpoint); |
|
724 |
|
725 rm.done(); |
|
726 } |
|
727 }; |
|
728 |
|
729 // Remove the back-end breakpoints |
|
730 Vector<IBreakpointDMContext> list = breakpointIDs.get(breakpoint); |
|
731 int count = 0; |
|
732 if (list != null) { |
|
733 for (IBreakpointDMContext bp : list) { |
|
734 fBreakpoints.removeBreakpoint(bp, removeRM); |
|
735 try { |
|
736 breakpoint.decrementInstallCount(); |
|
737 } catch (CoreException e) { |
|
738 } |
|
739 } |
|
740 count = list.size(); |
|
741 } |
|
742 removeRM.setDoneCount(count); |
|
743 } |
|
744 |
|
745 //------------------------------------------------------------------------- |
|
746 // modifyBreakpoint |
|
747 //------------------------------------------------------------------------- |
|
748 |
|
749 /** |
|
750 * Modify a platform breakpoint which can translate to quite a few updates |
|
751 * on the target... |
|
752 * |
|
753 * @param dmc |
|
754 * @param breakpoint |
|
755 * @param attributes |
|
756 * @param oldValues |
|
757 * @param rm |
|
758 */ |
|
759 private void modifyBreakpoint(final IBreakpointsTargetDMContext dmc, final ICBreakpoint breakpoint, |
|
760 final Map<String,Object> attributes, final IMarkerDelta oldValues, final RequestMonitor rm) |
|
761 { |
|
762 // Retrieve the breakpoint maps |
|
763 final Map<ICBreakpoint,Map<String,Object>> platformBPs = fPlatformBPs.get(dmc); |
|
764 assert platformBPs != null; |
|
765 |
|
766 final Map<ICBreakpoint, Vector<IBreakpointDMContext>> breakpointIDs = fBreakpointIDs.get(dmc); |
|
767 assert breakpointIDs != null; |
|
768 |
|
769 final Map<IBreakpointDMContext, ICBreakpoint> targetBPs = fTargetBPs.get(dmc); |
|
770 assert targetBPs != null; |
|
771 |
|
772 final Map<ICBreakpoint, Set<String>> threadsIDs = fBreakpointThreads.get(dmc); |
|
773 assert threadsIDs != null; |
|
774 |
|
775 // Minimal validation |
|
776 if (!platformBPs.containsKey(breakpoint)) { |
|
777 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, UNKNOWN_BREAKPOINT, null)); |
|
778 rm.done(); |
|
779 return; |
|
780 } |
|
781 |
|
782 // Check if the breakpoint is installed: it might not have been if it wasn't enabled at startup (Bug261082) |
|
783 // Or the installation might have failed; in this case, we still try to install it again because |
|
784 // some attribute might have changed which will make the install succeed. |
|
785 if (!breakpointIDs.containsKey(breakpoint) && !targetBPs.containsValue(breakpoint)) { |
|
786 // Install only if the breakpoint is enabled |
|
787 boolean bpEnabled = attributes.get(ICBreakpoint.ENABLED).equals(true) && fBreakpointManager.isEnabled(); |
|
788 if (bpEnabled) { |
|
789 attributes.put(ATTR_DEBUGGER_PATH, NULL_STRING); |
|
790 attributes.put(ATTR_THREAD_FILTER, extractThreads(dmc, breakpoint)); |
|
791 attributes.put(ATTR_THREAD_ID, NULL_STRING); |
|
792 determineDebuggerPath(dmc, attributes, new RequestMonitor(getExecutor(), rm) { |
|
793 @Override |
|
794 protected void handleSuccess() { |
|
795 installBreakpoint(dmc, breakpoint, attributes, rm); |
|
796 } |
|
797 }); |
|
798 } |
|
799 else { |
|
800 rm.done(); |
|
801 } |
|
802 return; |
|
803 } |
|
804 |
|
805 // Get the original breakpoint attributes |
|
806 final Map<String,Object> original_attributes = platformBPs.get(breakpoint); |
|
807 if (original_attributes == null) { |
|
808 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, INVALID_BREAKPOINT, null)); |
|
809 rm.done(); |
|
810 return; |
|
811 } |
|
812 |
|
813 // Determine the attributes delta |
|
814 final Map<String,Object> oldAttributes = new HashMap<String,Object>(original_attributes); |
|
815 oldAttributes.put(ATTR_THREAD_FILTER, threadsIDs.get(breakpoint)); |
|
816 |
|
817 final Set<String> newThreads = extractThreads(dmc, breakpoint); |
|
818 Map<String,Object> newAttributes = new HashMap<String,Object>(attributes); |
|
819 newAttributes.put(ATTR_THREAD_FILTER, newThreads); |
|
820 |
|
821 final Map<String,Object> attributesDelta = determineAttributesDelta(oldAttributes, newAttributes); |
|
822 |
|
823 // Get the list of back-end breakpoints |
|
824 final Vector<IBreakpointDMContext> oldTargetBPs = new Vector<IBreakpointDMContext>(breakpointIDs.get(breakpoint)); |
|
825 if (oldTargetBPs == null) { |
|
826 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, INVALID_BREAKPOINT, null)); |
|
827 rm.done(); |
|
828 return; |
|
829 } |
|
830 |
|
831 // We're all set for the breakpoint update. |
|
832 // |
|
833 // The path for a simple update is straightforward: |
|
834 // - For each back-end BP corresponding to a platform BP |
|
835 // - Send an update command to the back-end |
|
836 // - If the operation succeeded, update the data structures |
|
837 // - If the operation failed, try to roll-back |
|
838 // |
|
839 // In cases where the the back-end breakpoint cannot be |
|
840 // simply updated (e.g. thread filter modification), the old |
|
841 // breakpoint has to be removed and new one(s) inserted. |
|
842 // |
|
843 // The path for such an update is: |
|
844 // - Install the updated breakpoint |
|
845 // - In the operation succeeded |
|
846 // - Remove the old breakpoint(s) |
|
847 // - Perform any pending update |
|
848 |
|
849 // Update completion monitor |
|
850 final CountingRequestMonitor updateRM = new CountingRequestMonitor(getExecutor(), rm) { |
|
851 @Override |
|
852 protected void handleSuccess() { |
|
853 // Success: simply store the new attributes |
|
854 platformBPs.put(breakpoint, attributes); |
|
855 rm.done(); |
|
856 } |
|
857 |
|
858 @Override |
|
859 protected void handleError() { |
|
860 // Reset the breakpoint attributes. This will trigger a |
|
861 // breakpoint change event and the correct delta will be |
|
862 // computed, resulting in a correctly restored breakpoint |
|
863 // at the back-end. |
|
864 rollbackAttributes(breakpoint, oldValues); |
|
865 platformBPs.put(breakpoint, attributes); |
|
866 |
|
867 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); |
|
868 rm.done(); |
|
869 } |
|
870 }; |
|
871 |
|
872 // Everything OK: remove the old back-end breakpoints |
|
873 final Vector<IBreakpointDMContext> newTargetBPs = new Vector<IBreakpointDMContext>(); |
|
874 final CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) { |
|
875 @Override |
|
876 protected void handleSuccess() { |
|
877 // All right! Save the new list and perform the final update |
|
878 Map<ICBreakpoint, Vector<IBreakpointDMContext>> breakpointIDs = fBreakpointIDs.get(dmc); |
|
879 if (breakpointIDs == null) { |
|
880 rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_BREAKPOINT, null)); |
|
881 rm.done(); |
|
882 return; |
|
883 } |
|
884 breakpointIDs.put(breakpoint, newTargetBPs); |
|
885 for (IBreakpointDMContext ref : newTargetBPs) { |
|
886 fBreakpoints.updateBreakpoint(ref, attributesDelta, updateRM); |
|
887 } |
|
888 updateRM.setDoneCount(newTargetBPs.size()); |
|
889 }}; |
|
890 |
|
891 // New back-end breakpoints insertion monitor |
|
892 // Holds the list of new back-end breakpoint contexts of the platform breakpoint |
|
893 final DataRequestMonitor<Vector<IBreakpointDMContext>> insertRM = |
|
894 new DataRequestMonitor<Vector<IBreakpointDMContext>>(getExecutor(), null) { |
|
895 |
|
896 @Override |
|
897 // In theory, we could have had a partial success and the original threads |
|
898 // list would be invalid. We think it is highly unlikely so we assume that |
|
899 // either everything went fine or else everything failed. |
|
900 protected void handleSuccess() { |
|
901 // Get the list of new back-end breakpoints contexts |
|
902 newTargetBPs.addAll(getData()); |
|
903 threadsIDs.put(breakpoint, newThreads); |
|
904 for (IBreakpointDMContext ref : oldTargetBPs) { |
|
905 fBreakpoints.removeBreakpoint(ref, removeRM); |
|
906 try { |
|
907 breakpoint.decrementInstallCount(); // A tad early but it should work... |
|
908 } catch (CoreException e) { |
|
909 } |
|
910 } |
|
911 removeRM.setDoneCount(oldTargetBPs.size()); |
|
912 } |
|
913 |
|
914 @Override |
|
915 protected void handleError() { |
|
916 // Keep the old threads list and reset the attributes |
|
917 // (bad attributes are the likely cause of failure) |
|
918 updateRM.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); |
|
919 updateRM.setDoneCount(0); |
|
920 } |
|
921 }; |
|
922 |
|
923 // If the changes in the breakpoint attributes justify it, install a |
|
924 // new set of back-end breakpoint(s) and then update them |
|
925 if (needsResinstallation(attributesDelta)) { |
|
926 reinstallBreakpoint(dmc, breakpoint, attributes, newThreads, insertRM); |
|
927 } |
|
928 else { |
|
929 // Update the back-end breakpoint(s) state |
|
930 for (IBreakpointDMContext ref : oldTargetBPs) { |
|
931 fBreakpoints.updateBreakpoint(ref, attributesDelta, updateRM); |
|
932 } |
|
933 updateRM.setDoneCount(oldTargetBPs.size()); |
|
934 } |
|
935 } |
|
936 |
|
937 /** |
|
938 * Re-install the back-end breakpoints |
|
939 * |
|
940 * @param context the target context |
|
941 * @param breakpoint the platform breakpoint |
|
942 * @param attributes breakpoint augmented attributes |
|
943 * @param threads list of threads where breakpoint is to be installed |
|
944 * @param drm will contain the list of successfully installed back-end breakpoints |
|
945 */ |
|
946 private void reinstallBreakpoint(final IBreakpointsTargetDMContext context, final ICBreakpoint breakpoint, |
|
947 final Map<String,Object> attributes, Set<String> threads, final DataRequestMonitor<Vector<IBreakpointDMContext>> drm) |
|
948 { |
|
949 // Our new list of back-end breakpoints. Built as we go. |
|
950 final Vector<IBreakpointDMContext> breakpointList = new Vector<IBreakpointDMContext>(); |
|
951 |
|
952 // Counting monitor for the new back-end breakpoints to install |
|
953 // Once we're done, return the new list of back-end breakpoints contexts |
|
954 final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), drm) { |
|
955 @Override |
|
956 protected void handleSuccess() { |
|
957 // Report whatever we have managed to install |
|
958 // It is very likely installation either succeeded or failed for all |
|
959 drm.setData(breakpointList); |
|
960 drm.done(); |
|
961 } |
|
962 }; |
|
963 installRM.setDoneCount(threads.size()); |
|
964 |
|
965 // And install the new back-end breakpoints |
|
966 for (String thread : threads) { |
|
967 // Convert the breakpoint attributes for the back-end |
|
968 // Refresh the set of attributes at each iteration just in case... |
|
969 Map<String,Object> attrs = convertToTargetBreakpoint(breakpoint, attributes); |
|
970 if (!fBreakpointManager.isEnabled()) { |
|
971 attrs.put(MIBreakpoints.IS_ENABLED, false); |
|
972 } |
|
973 // Add the secret ingredient.. |
|
974 attrs.put(MIBreakpointDMData.THREAD_ID, thread); |
|
975 |
|
976 // Then install the spiked breakpoint |
|
977 fBreakpoints.insertBreakpoint(context, attrs, |
|
978 new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), installRM) { |
|
979 @Override |
|
980 protected void handleSuccess() { |
|
981 // Add the new back-end breakpoint context to the list |
|
982 breakpointList.add(getData()); |
|
983 try { |
|
984 breakpoint.incrementInstallCount(); |
|
985 } catch (CoreException e) { |
|
986 } |
|
987 installRM.done(); |
|
988 } |
|
989 |
|
990 @Override |
|
991 protected void handleError() { |
|
992 // Add the new back-end breakpoint context to the list |
|
993 installRM.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); |
|
994 installRM.done(); |
|
995 } |
|
996 }); |
|
997 } |
|
998 } |
|
999 |
|
1000 /////////////////////////////////////////////////////////////////////////// |
|
1001 // IBreakpointManagerListener implementation |
|
1002 /////////////////////////////////////////////////////////////////////////// |
|
1003 |
|
1004 /* (non-Javadoc) |
|
1005 * @see org.eclipse.debug.core.IBreakpointManagerListener#breakpointManagerEnablementChanged(boolean) |
|
1006 */ |
|
1007 public void breakpointManagerEnablementChanged(boolean enabled) { |
|
1008 |
|
1009 // Only modify enabled breakpoints |
|
1010 for (IBreakpointsTargetDMContext context : fBreakpointIDs.keySet()) { |
|
1011 for (ICBreakpoint breakpoint : fBreakpointIDs.get(context).keySet()) { |
|
1012 try { |
|
1013 if (breakpoint.isEnabled()) { |
|
1014 for (IBreakpointDMContext ref : fBreakpointIDs.get(context).get(breakpoint)) { |
|
1015 Map<String,Object> delta = new HashMap<String,Object>(); |
|
1016 delta.put(MIBreakpoints.IS_ENABLED, enabled); |
|
1017 fBreakpoints.updateBreakpoint(ref, delta, new RequestMonitor(getExecutor(), null)); |
|
1018 } |
|
1019 } |
|
1020 } catch (CoreException e) { |
|
1021 } |
|
1022 } |
|
1023 } |
|
1024 } |
|
1025 |
|
1026 /////////////////////////////////////////////////////////////////////////// |
|
1027 // IBreakpointListener implementation |
|
1028 /////////////////////////////////////////////////////////////////////////// |
|
1029 |
|
1030 /* (non-Javadoc) |
|
1031 * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint) |
|
1032 */ |
|
1033 @ThreadSafe |
|
1034 public void breakpointAdded(final IBreakpoint breakpoint) { |
|
1035 |
|
1036 if (supportsBreakpoint(breakpoint)) { |
|
1037 try { |
|
1038 // Retrieve the breakpoint attributes |
|
1039 @SuppressWarnings("unchecked") |
|
1040 final Map<String, Object> attrs = breakpoint.getMarker().getAttributes(); |
|
1041 |
|
1042 getExecutor().execute(new DsfRunnable() { |
|
1043 public void run() { |
|
1044 final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { |
|
1045 @Override |
|
1046 protected void handleError() { |
|
1047 if (getStatus().getSeverity() == IStatus.ERROR) { |
|
1048 GdbPlugin.getDefault().getLog().log(getStatus()); |
|
1049 } |
|
1050 } |
|
1051 }; |
|
1052 countingRm.setDoneCount(fPlatformBPs.size()); |
|
1053 |
|
1054 // Install the breakpoint in all the execution contexts |
|
1055 for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { |
|
1056 determineDebuggerPath(dmc, attrs, |
|
1057 new RequestMonitor(getExecutor(), countingRm) { |
|
1058 @Override |
|
1059 protected void handleSuccess() { |
|
1060 installBreakpoint(dmc, (ICBreakpoint) breakpoint, |
|
1061 attrs, countingRm); |
|
1062 } |
|
1063 }); |
|
1064 } |
|
1065 } |
|
1066 }); |
|
1067 } catch (CoreException e) { |
|
1068 } catch (RejectedExecutionException e) { |
|
1069 } |
|
1070 } |
|
1071 } |
|
1072 |
|
1073 /** |
|
1074 * @param bp |
|
1075 * @return |
|
1076 * @throws CoreException |
|
1077 */ |
|
1078 private IDsfBreakpointExtension getFilterExtension(ICBreakpoint bp) throws CoreException { |
|
1079 return (IDsfBreakpointExtension) bp.getExtension(GDB_DEBUG_MODEL_ID, ICBreakpointExtension.class); |
|
1080 } |
|
1081 |
|
1082 /* (non-Javadoc) |
|
1083 * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) |
|
1084 */ |
|
1085 public void breakpointChanged(final IBreakpoint breakpoint, final IMarkerDelta delta) { |
|
1086 |
|
1087 if (supportsBreakpoint(breakpoint)) { |
|
1088 |
|
1089 try { |
|
1090 // Retrieve the breakpoint attributes |
|
1091 @SuppressWarnings("unchecked") |
|
1092 final Map<String, Object> attrs = breakpoint.getMarker().getAttributes(); |
|
1093 if (!fBreakpointManager.isEnabled()) { |
|
1094 attrs.put(ICBreakpoint.ENABLED, false); |
|
1095 } |
|
1096 |
|
1097 // Modify the breakpoint in all the target contexts |
|
1098 getExecutor().execute( new DsfRunnable() { |
|
1099 public void run() { |
|
1100 |
|
1101 // If the breakpoint is currently being updated, queue the request and exit |
|
1102 if (fPendingRequests.contains(breakpoint)) { |
|
1103 fPendingBreakpoints.add(breakpoint); |
|
1104 return; |
|
1105 } |
|
1106 |
|
1107 // Keep track of the updates |
|
1108 final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { |
|
1109 @Override |
|
1110 protected void handleCompleted() { |
|
1111 |
|
1112 if (!isSuccess()) { |
|
1113 if (getStatus().getSeverity() == IStatus.ERROR) { |
|
1114 GdbPlugin.getDefault().getLog().log(getStatus()); |
|
1115 } |
|
1116 } |
|
1117 |
|
1118 // Indicate that the pending request has completed |
|
1119 fPendingRequests.remove(breakpoint); |
|
1120 |
|
1121 // Process the next pending update for this breakpoint |
|
1122 if (fPendingBreakpoints.contains(breakpoint)) { |
|
1123 fPendingBreakpoints.remove(breakpoint); |
|
1124 breakpointChanged(breakpoint, delta); |
|
1125 } |
|
1126 } |
|
1127 }; |
|
1128 countingRm.setDoneCount(fPlatformBPs.size()); |
|
1129 |
|
1130 // Mark the breakpoint as being updated and go |
|
1131 fPendingRequests.add(breakpoint); |
|
1132 |
|
1133 // Modify the breakpoint in all the execution contexts |
|
1134 for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { |
|
1135 determineDebuggerPath(dmc, attrs, |
|
1136 new RequestMonitor(getExecutor(), countingRm) { |
|
1137 @Override |
|
1138 protected void handleSuccess() { |
|
1139 modifyBreakpoint(dmc, (ICBreakpoint) breakpoint, attrs, delta, new RequestMonitor(getExecutor(), countingRm)); |
|
1140 } |
|
1141 }); |
|
1142 } |
|
1143 } |
|
1144 }); |
|
1145 } catch (CoreException e) { |
|
1146 } catch (RejectedExecutionException e) { |
|
1147 } |
|
1148 } |
|
1149 } |
|
1150 |
|
1151 /* (non-Javadoc) |
|
1152 * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) |
|
1153 */ |
|
1154 public void breakpointRemoved(final IBreakpoint breakpoint, IMarkerDelta delta) { |
|
1155 |
|
1156 if (supportsBreakpoint(breakpoint)) { |
|
1157 try { |
|
1158 getExecutor().execute(new DsfRunnable() { |
|
1159 public void run() { |
|
1160 CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { |
|
1161 @Override |
|
1162 protected void handleError() { |
|
1163 if (getStatus().getSeverity() == IStatus.ERROR) { |
|
1164 GdbPlugin.getDefault().getLog().log(getStatus()); |
|
1165 } |
|
1166 } |
|
1167 }; |
|
1168 countingRm.setDoneCount(fPlatformBPs.size()); |
|
1169 |
|
1170 // Remove the breakpoint in all the execution contexts |
|
1171 for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { |
|
1172 if (fPlatformBPs.get(dmc).containsKey(breakpoint)) { |
|
1173 uninstallBreakpoint(dmc, (ICBreakpoint) breakpoint, countingRm); |
|
1174 } |
|
1175 } |
|
1176 } |
|
1177 }); |
|
1178 } catch (RejectedExecutionException e) { |
|
1179 } |
|
1180 } |
|
1181 } |
|
1182 |
|
1183 /////////////////////////////////////////////////////////////////////////// |
|
1184 // IServiceEventListener |
|
1185 /////////////////////////////////////////////////////////////////////////// |
|
1186 |
|
1187 //------------------------------------------------------------------------- |
|
1188 // Breakpoints |
|
1189 //------------------------------------------------------------------------- |
|
1190 |
|
1191 @DsfServiceEventHandler |
|
1192 public void eventDispatched(BreakpointAddedEvent e) { |
|
1193 // Nothing to do - already handled by breakpointAdded() |
|
1194 } |
|
1195 |
|
1196 @DsfServiceEventHandler |
|
1197 public void eventDispatched(BreakpointUpdatedEvent e) { |
|
1198 // Nothing to do - already handled by breakpointChanged() |
|
1199 } |
|
1200 |
|
1201 @DsfServiceEventHandler |
|
1202 public void eventDispatched(BreakpointRemovedEvent e) { |
|
1203 // Nothing to do - already handled by breakpointRemoved() |
|
1204 } |
|
1205 |
|
1206 /* |
|
1207 * When a watchpoint goes out of scope, it is automatically removed from |
|
1208 * the back-end. To keep our internal state synchronized, we have to |
|
1209 * remove it from our breakpoints maps. |
|
1210 * Unfortunately, GDB doesn't generate the correct event... |
|
1211 */ |
|
1212 @DsfServiceEventHandler |
|
1213 public void eventDispatched(MIWatchpointScopeEvent e) { |
|
1214 } |
|
1215 |
|
1216 //------------------------------------------------------------------------- |
|
1217 // Breakpoint actions |
|
1218 //------------------------------------------------------------------------- |
|
1219 |
|
1220 @DsfServiceEventHandler |
|
1221 public void eventDispatched(SuspendedEvent e) { |
|
1222 |
|
1223 if (e.getMIEvent() instanceof MIBreakpointHitEvent) { |
|
1224 MIBreakpointHitEvent evt = (MIBreakpointHitEvent) e.getMIEvent(); |
|
1225 performBreakpointAction(evt.getDMContext(), evt.getNumber()); |
|
1226 return; |
|
1227 } |
|
1228 |
|
1229 if (e.getMIEvent() instanceof MIWatchpointTriggerEvent) { |
|
1230 MIWatchpointTriggerEvent evt = (MIWatchpointTriggerEvent) e.getMIEvent(); |
|
1231 performBreakpointAction(evt.getDMContext(), evt.getNumber()); |
|
1232 return; |
|
1233 } |
|
1234 } |
|
1235 |
|
1236 private void performBreakpointAction(final IDMContext context, int number) { |
|
1237 // Identify the platform breakpoint |
|
1238 final ICBreakpoint breakpoint = findPlatformBreakpoint(number); |
|
1239 |
|
1240 // Perform the actions asynchronously (otherwise we can have a deadlock...) |
|
1241 new Job("Breakpoint action") { //$NON-NLS-1$ |
|
1242 { setSystem(true); } |
|
1243 @Override |
|
1244 protected IStatus run(IProgressMonitor monitor) { |
|
1245 fBreakpointActionManager.executeActions(breakpoint, new BreakpointActionAdapter(getExecutor(), getServicesTracker(), context)); |
|
1246 return Status.OK_STATUS; |
|
1247 }; |
|
1248 }.schedule(); |
|
1249 } |
|
1250 |
|
1251 // Helper function to locate the platform breakpoint corresponding |
|
1252 // to the target breakpoint/watchpoint that was just hit |
|
1253 |
|
1254 // FIXME: (Bug228703) Need a way to identify the correct context where the BP was hit |
|
1255 private ICBreakpoint findPlatformBreakpoint(int targetBreakpointID) { |
|
1256 Set<IBreakpointsTargetDMContext> targets = fTargetBPs.keySet(); |
|
1257 for (IBreakpointsTargetDMContext target : targets) { |
|
1258 Map<IBreakpointDMContext, ICBreakpoint> bps = fTargetBPs.get(target); |
|
1259 Set<IBreakpointDMContext> contexts = bps.keySet(); |
|
1260 for (IBreakpointDMContext context : contexts) { |
|
1261 if (context instanceof MIBreakpointDMContext) { |
|
1262 MIBreakpointDMContext ctx = (MIBreakpointDMContext) context; |
|
1263 if (ctx.getReference() == targetBreakpointID) { |
|
1264 return bps.get(context); |
|
1265 } |
|
1266 } |
|
1267 } |
|
1268 } |
|
1269 return null; |
|
1270 } |
|
1271 |
|
1272 //------------------------------------------------------------------------- |
|
1273 // Session exit |
|
1274 //------------------------------------------------------------------------- |
|
1275 |
|
1276 /** |
|
1277 * @since 1.1 |
|
1278 * @nooverride This method is not intended to be re-implemented or extended by clients. |
|
1279 * @noreference This method is not intended to be referenced by clients. |
|
1280 */ |
|
1281 @DsfServiceEventHandler |
|
1282 public void eventDispatched(ICommandControlShutdownDMEvent e) { |
|
1283 terminated(); |
|
1284 } |
|
1285 |
|
1286 private void terminated() { |
|
1287 // Reset the breakpoint install count |
|
1288 for (IBreakpointsTargetDMContext ctx : fPlatformBPs.keySet()) { |
|
1289 Map<ICBreakpoint, Map<String, Object>> breakpoints = fPlatformBPs.get(ctx); |
|
1290 clearBreakpointStatus(breakpoints.keySet().toArray(new ICBreakpoint[breakpoints.size()]), ctx); |
|
1291 } |
|
1292 // This will prevent Shutdown() from trying to remove bps from a |
|
1293 // backend that has already shutdown |
|
1294 fPlatformBPs.clear(); |
|
1295 } |
|
1296 |
|
1297 /////////////////////////////////////////////////////////////////////////// |
|
1298 // Breakpoint status handling functions |
|
1299 /////////////////////////////////////////////////////////////////////////// |
|
1300 |
|
1301 /** |
|
1302 * @param bps |
|
1303 */ |
|
1304 private void clearBreakpointStatus(final ICBreakpoint[] bps, final IBreakpointsTargetDMContext ctx) |
|
1305 { |
|
1306 new Job("Clear Breakpoints Status") { //$NON-NLS-1$ |
|
1307 @Override |
|
1308 protected IStatus run(IProgressMonitor monitor) { |
|
1309 IWorkspaceRunnable wr = new IWorkspaceRunnable() { |
|
1310 public void run(IProgressMonitor monitor) throws CoreException { |
|
1311 // For every platform breakpoint that has at least one target breakpoint installed |
|
1312 // we must decrement the install count, for every target breakpoint. |
|
1313 // Note that we cannot simply call resetInstallCount() because another |
|
1314 // launch may be using the same platform breakpoint. |
|
1315 Map<ICBreakpoint, Vector<IBreakpointDMContext>> breakpoints = fBreakpointIDs.get(ctx); |
|
1316 for (ICBreakpoint breakpoint : breakpoints.keySet()) { |
|
1317 Vector<IBreakpointDMContext> targetBps = breakpoints.get(breakpoint); |
|
1318 for (int i=0; i<targetBps.size(); i++) { |
|
1319 breakpoint.decrementInstallCount(); |
|
1320 } |
|
1321 } |
|
1322 } |
|
1323 }; |
|
1324 |
|
1325 // First clear any problem markers |
|
1326 for (IMarker marker : fBreakpointMarkerProblems.values()) { |
|
1327 if (marker != null) { |
|
1328 try { |
|
1329 marker.delete(); |
|
1330 } catch (CoreException e) { |
|
1331 } |
|
1332 } |
|
1333 } |
|
1334 fBreakpointMarkerProblems.clear(); |
|
1335 |
|
1336 // Create the scheduling rule to clear all bp planted. |
|
1337 ISchedulingRule rule = null; |
|
1338 List<ISchedulingRule> markerRules = new ArrayList<ISchedulingRule>(); |
|
1339 for (ICBreakpoint bp : bps) { |
|
1340 IMarker marker = bp.getMarker(); |
|
1341 if (marker != null) { |
|
1342 ISchedulingRule markerRule = |
|
1343 ResourcesPlugin.getWorkspace().getRuleFactory().markerRule( |
|
1344 marker.getResource()); |
|
1345 if (markerRule == null) { |
|
1346 markerRules = null; |
|
1347 break; |
|
1348 } else { |
|
1349 markerRules.add(markerRule); |
|
1350 } |
|
1351 } |
|
1352 } |
|
1353 if (markerRules != null) { |
|
1354 rule = MultiRule.combine(markerRules.toArray(new ISchedulingRule[markerRules.size()])); |
|
1355 } |
|
1356 |
|
1357 try { |
|
1358 ResourcesPlugin.getWorkspace().run(wr, rule, 0, null); |
|
1359 } catch (CoreException e) { |
|
1360 return e.getStatus(); |
|
1361 } |
|
1362 return Status.OK_STATUS; |
|
1363 } |
|
1364 }.schedule(); |
|
1365 } |
|
1366 |
|
1367 /////////////////////////////////////////////////////////////////////////// |
|
1368 // Support functions |
|
1369 /////////////////////////////////////////////////////////////////////////// |
|
1370 |
|
1371 /** |
|
1372 * supportsBreakpoint |
|
1373 * |
|
1374 * Indicates if it is breakpoint we can deal with. For now, it boils down |
|
1375 * to a CDI breakpoint... |
|
1376 * |
|
1377 * @param bp |
|
1378 * @return |
|
1379 */ |
|
1380 private boolean supportsBreakpoint(IBreakpoint bp) { |
|
1381 if (bp instanceof ICBreakpoint && bp.getModelIdentifier().equals(fDebugModelId)) { |
|
1382 IMarker marker = bp.getMarker(); |
|
1383 if (marker != null) { |
|
1384 return true; |
|
1385 } |
|
1386 } |
|
1387 return false; |
|
1388 } |
|
1389 |
|
1390 /** |
|
1391 * determineDebuggerPath |
|
1392 * |
|
1393 * Adds the path to the source file to the set of attributes |
|
1394 * (for the debugger). |
|
1395 * |
|
1396 * @param dmc |
|
1397 * @param attributes |
|
1398 * @param rm |
|
1399 */ |
|
1400 private void determineDebuggerPath(IBreakpointsTargetDMContext dmc, |
|
1401 final Map<String, Object> attributes, final RequestMonitor rm) |
|
1402 { |
|
1403 String hostPath = (String) attributes.get(ICBreakpoint.SOURCE_HANDLE); |
|
1404 |
|
1405 if (hostPath != null) { |
|
1406 |
|
1407 ISourceLookupDMContext srcDmc = DMContexts.getAncestorOfType(dmc, ISourceLookupDMContext.class); |
|
1408 if (srcDmc != null) { |
|
1409 fSourceLookup.getDebuggerPath(srcDmc, hostPath, |
|
1410 new DataRequestMonitor<String>(getExecutor(), rm) { |
|
1411 @Override |
|
1412 protected void handleSuccess() { |
|
1413 attributes.put(ATTR_DEBUGGER_PATH, adjustDebuggerPath(getData())); |
|
1414 rm.done(); |
|
1415 } |
|
1416 }); |
|
1417 } else { |
|
1418 // Source lookup not available for given context, use the host |
|
1419 // path for the debugger path. |
|
1420 attributes.put(ATTR_DEBUGGER_PATH, adjustDebuggerPath(hostPath)); |
|
1421 rm.done(); |
|
1422 } |
|
1423 } else { |
|
1424 // Some types of breakpoints do not require a path |
|
1425 // (e.g. watchpoints) |
|
1426 rm.done(); |
|
1427 } |
|
1428 } |
|
1429 |
|
1430 /** |
|
1431 * See bug232415 |
|
1432 * |
|
1433 * @param path the absolute path to the source file |
|
1434 * @return |
|
1435 */ |
|
1436 private String adjustDebuggerPath(String path) { |
|
1437 String result = path; |
|
1438 // Make it MinGW-specific |
|
1439 if (Platform.getOS().startsWith("win")) { //$NON-NLS-1$ |
|
1440 if (!path.startsWith("/")) { //$NON-NLS-1$ |
|
1441 result = path.substring(path.lastIndexOf('\\') + 1); |
|
1442 } |
|
1443 } |
|
1444 return result; |
|
1445 } |
|
1446 |
|
1447 /** |
|
1448 * Determine the set of modified attributes. |
|
1449 * Elementary set operations in full action :-) |
|
1450 * |
|
1451 * @param oldAttributes |
|
1452 * @param newAttributes |
|
1453 * @return |
|
1454 */ |
|
1455 private Map<String, Object> determineAttributesDelta(Map<String, Object> oldAttributes, Map<String, Object> newAttributes) { |
|
1456 |
|
1457 Map<String, Object> delta = new HashMap<String,Object>(); |
|
1458 |
|
1459 Set<String> oldKeySet = oldAttributes.keySet(); |
|
1460 Set<String> newKeySet = newAttributes.keySet(); |
|
1461 |
|
1462 Set<String> commonKeys = new HashSet<String>(newKeySet); commonKeys.retainAll(oldKeySet); |
|
1463 Set<String> addedKeys = new HashSet<String>(newKeySet); addedKeys.removeAll(oldKeySet); |
|
1464 Set<String> removedKeys = new HashSet<String>(oldKeySet); removedKeys.removeAll(newKeySet); |
|
1465 |
|
1466 // Add the modified attributes |
|
1467 for (String key : commonKeys) { |
|
1468 if (!(oldAttributes.get(key).equals(newAttributes.get(key)))) |
|
1469 delta.put(key, newAttributes.get(key)); |
|
1470 } |
|
1471 |
|
1472 // Add the new attributes |
|
1473 for (String key : addedKeys) { |
|
1474 delta.put(key, newAttributes.get(key)); |
|
1475 } |
|
1476 |
|
1477 // Remove the deleted attributes |
|
1478 for (String key : removedKeys) { |
|
1479 delta.put(key, null); |
|
1480 } |
|
1481 |
|
1482 return convertedAttributes(delta); |
|
1483 } |
|
1484 |
|
1485 /** |
|
1486 * Converts ICBreakpoint attributes to IBreakpoints attributes. |
|
1487 * |
|
1488 * @param cdt_attributes |
|
1489 * @return |
|
1490 */ |
|
1491 private Map<String, Object> convertedAttributes(Map<String, Object> cdt_attributes) { |
|
1492 |
|
1493 Map<String,Object> result = new HashMap<String,Object>(); |
|
1494 |
|
1495 // IBreakpoint attributes |
|
1496 if (cdt_attributes.containsKey(ATTR_DEBUGGER_PATH)) |
|
1497 result.put(MIBreakpoints.FILE_NAME, cdt_attributes.get(ATTR_DEBUGGER_PATH)); |
|
1498 |
|
1499 if (cdt_attributes.containsKey(IMarker.LINE_NUMBER)) |
|
1500 result.put(MIBreakpoints.LINE_NUMBER, cdt_attributes.get(IMarker.LINE_NUMBER)); |
|
1501 |
|
1502 // ICLineBreakpoint attributes |
|
1503 if (cdt_attributes.containsKey(ICLineBreakpoint.FUNCTION)) |
|
1504 result.put(MIBreakpoints.FUNCTION, cdt_attributes.get(ICLineBreakpoint.FUNCTION)); |
|
1505 |
|
1506 if (cdt_attributes.containsKey(ICLineBreakpoint.ADDRESS)) |
|
1507 result.put(MIBreakpoints.ADDRESS, cdt_attributes.get(ICLineBreakpoint.ADDRESS)); |
|
1508 |
|
1509 // ICBreakpoint attributes |
|
1510 if (cdt_attributes.containsKey(ICBreakpoint.CONDITION)) |
|
1511 result.put(MIBreakpoints.CONDITION, cdt_attributes.get(ICBreakpoint.CONDITION)); |
|
1512 |
|
1513 if (cdt_attributes.containsKey(ICBreakpoint.IGNORE_COUNT)) |
|
1514 result.put(MIBreakpoints.IGNORE_COUNT, cdt_attributes.get(ICBreakpoint.IGNORE_COUNT)); |
|
1515 |
|
1516 if (cdt_attributes.containsKey(ICBreakpoint.ENABLED)) |
|
1517 result.put(MIBreakpoints.IS_ENABLED, cdt_attributes.get(ICBreakpoint.ENABLED)); |
|
1518 |
|
1519 // ICWatchpoint attributes |
|
1520 if (cdt_attributes.containsKey(ICWatchpoint.EXPRESSION)) |
|
1521 result.put(MIBreakpoints.EXPRESSION, cdt_attributes.get(ICWatchpoint.EXPRESSION)); |
|
1522 |
|
1523 if (cdt_attributes.containsKey(ICWatchpoint.READ)) |
|
1524 result.put(MIBreakpoints.READ, cdt_attributes.get(ICWatchpoint.READ)); |
|
1525 |
|
1526 if (cdt_attributes.containsKey(ICWatchpoint.WRITE)) |
|
1527 result.put(MIBreakpoints.WRITE, cdt_attributes.get(ICWatchpoint.WRITE)); |
|
1528 |
|
1529 // Threads |
|
1530 if (cdt_attributes.containsKey(ATTR_THREAD_FILTER)) |
|
1531 result.put(ATTR_THREAD_FILTER, cdt_attributes.get(ATTR_THREAD_FILTER)); |
|
1532 |
|
1533 return result; |
|
1534 } |
|
1535 |
|
1536 /** |
|
1537 * Figure out the corresponding number of back-end breakpoints |
|
1538 * Even though the thread IDs are usually integers, they are |
|
1539 * stored as strings in CBreakpoints. |
|
1540 * |
|
1541 * @param attributes |
|
1542 * @return |
|
1543 */ |
|
1544 @SuppressWarnings("unchecked") |
|
1545 private Set<String> getThreads(Map<String, Object> attributes) { |
|
1546 Set<String> threads = (Set<String>) attributes.get(ATTR_THREAD_FILTER); |
|
1547 if (threads == null) { |
|
1548 threads = new HashSet<String>(); |
|
1549 threads.add("0"); // Thread 0 means all threads //$NON-NLS-1$ |
|
1550 } |
|
1551 return threads; |
|
1552 } |
|
1553 |
|
1554 /** |
|
1555 * Get the list of threads from the platform breakpoint attributes |
|
1556 * |
|
1557 * @param breakpoint |
|
1558 * @return |
|
1559 */ |
|
1560 private Set<String> extractThreads(IBreakpointsTargetDMContext context, ICBreakpoint breakpoint) { |
|
1561 Set<String> results = new HashSet<String>(); |
|
1562 |
|
1563 // Find the ancestor |
|
1564 List<IExecutionDMContext[]> threads = new ArrayList<IExecutionDMContext[]>(1); |
|
1565 |
|
1566 try { |
|
1567 // Retrieve the targets |
|
1568 IDsfBreakpointExtension filterExtension = getFilterExtension(breakpoint); |
|
1569 IContainerDMContext[] targets = filterExtension.getTargetFilters(); |
|
1570 |
|
1571 // If no target is present, breakpoint applies to all. |
|
1572 if (targets.length == 0) { |
|
1573 results.add("0"); //$NON-NLS-1$ |
|
1574 return results; |
|
1575 } |
|
1576 |
|
1577 // Extract the thread IDs (if there is none, we are covered) |
|
1578 for (IContainerDMContext ctxt : targets) { |
|
1579 if (DMContexts.isAncestorOf(ctxt, context)) { |
|
1580 threads.add(filterExtension.getThreadFilters(ctxt)); |
|
1581 } |
|
1582 } |
|
1583 } catch (CoreException e1) { |
|
1584 } |
|
1585 |
|
1586 if (supportsThreads(breakpoint)) { |
|
1587 for (IExecutionDMContext[] targetThreads : threads) { |
|
1588 if (targetThreads != null) { |
|
1589 for (IExecutionDMContext thread : targetThreads) { |
|
1590 if (thread instanceof IMIExecutionDMContext) { |
|
1591 IMIExecutionDMContext dmc = (IMIExecutionDMContext) thread; |
|
1592 results.add(((Integer) dmc.getThreadId()).toString()); |
|
1593 } |
|
1594 } |
|
1595 } else { |
|
1596 results.add("0"); //$NON-NLS-1$ |
|
1597 break; |
|
1598 } |
|
1599 } |
|
1600 } else { |
|
1601 results.add("0"); //$NON-NLS-1$ |
|
1602 } |
|
1603 |
|
1604 return results; |
|
1605 } |
|
1606 |
|
1607 /////////////////////////////////////////////////////////////////////////// |
|
1608 // Non-generic (MI-specific) functions |
|
1609 /////////////////////////////////////////////////////////////////////////// |
|
1610 |
|
1611 /** |
|
1612 * Create a target breakpoint from an ICBreakpoint |
|
1613 * |
|
1614 * @param breakpoint |
|
1615 * @param attributes |
|
1616 * @return |
|
1617 */ |
|
1618 protected Map<String,Object> convertToTargetBreakpoint(ICBreakpoint breakpoint, Map<String,Object> attributes) { |
|
1619 |
|
1620 Map<String, Object> properties = new HashMap<String, Object>(); |
|
1621 |
|
1622 if (breakpoint instanceof ICWatchpoint) { |
|
1623 // Convert the CDI watchpoint to an IBreakpoint |
|
1624 properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.WATCHPOINT); |
|
1625 properties.put(MIBreakpoints.EXPRESSION, attributes.get(ICWatchpoint.EXPRESSION)); |
|
1626 properties.put(MIBreakpoints.READ, attributes.get(ICWatchpoint.READ)); |
|
1627 properties.put(MIBreakpoints.WRITE, attributes.get(ICWatchpoint.WRITE)); |
|
1628 } |
|
1629 else if (breakpoint instanceof ICLineBreakpoint) { |
|
1630 // Convert the CDI breakpoint to an IBreakpoint |
|
1631 properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.BREAKPOINT); |
|
1632 properties.put(MIBreakpoints.FILE_NAME, attributes.get(ATTR_DEBUGGER_PATH)); |
|
1633 properties.put(MIBreakpoints.LINE_NUMBER, attributes.get(IMarker.LINE_NUMBER)); |
|
1634 properties.put(MIBreakpoints.FUNCTION, attributes.get(ICLineBreakpoint.FUNCTION)); |
|
1635 properties.put(MIBreakpoints.ADDRESS, attributes.get(ICLineBreakpoint.ADDRESS)); |
|
1636 } else { |
|
1637 // catchpoint? |
|
1638 } |
|
1639 |
|
1640 // Common fields |
|
1641 properties.put(MIBreakpoints.CONDITION, attributes.get(ICBreakpoint.CONDITION)); |
|
1642 properties.put(MIBreakpoints.IGNORE_COUNT, attributes.get(ICBreakpoint.IGNORE_COUNT)); |
|
1643 properties.put(MIBreakpoints.IS_ENABLED, attributes.get(ICBreakpoint.ENABLED)); |
|
1644 properties.put(MIBreakpointDMData.THREAD_ID, attributes.get(ATTR_THREAD_ID)); |
|
1645 |
|
1646 // Adjust for "skip-all" |
|
1647 if (!fBreakpointManager.isEnabled()) { |
|
1648 properties.put(MIBreakpoints.IS_ENABLED, false); |
|
1649 } |
|
1650 |
|
1651 return properties; |
|
1652 } |
|
1653 |
|
1654 /** |
|
1655 * Determine if the modified attributes necessitate |
|
1656 * a breakpoint removal/re-installation |
|
1657 * |
|
1658 * @param delta |
|
1659 * @return |
|
1660 */ |
|
1661 protected boolean needsResinstallation(Map<String,Object> delta) { |
|
1662 |
|
1663 // Check if there is any modified attribute |
|
1664 if (delta == null) |
|
1665 return false; |
|
1666 |
|
1667 // Check the "critical" attributes |
|
1668 if (delta.containsKey(ATTR_DEBUGGER_PATH) // File name |
|
1669 || delta.containsKey(MIBreakpoints.LINE_NUMBER) // Line number |
|
1670 || delta.containsKey(MIBreakpoints.FUNCTION) // Function name |
|
1671 || delta.containsKey(MIBreakpoints.ADDRESS) // Absolute address |
|
1672 || delta.containsKey(ATTR_THREAD_FILTER) // Thread ID |
|
1673 || delta.containsKey(MIBreakpoints.EXPRESSION) // Watchpoint expression |
|
1674 || delta.containsKey(MIBreakpoints.READ) // Watchpoint type |
|
1675 || delta.containsKey(MIBreakpoints.WRITE)) { // Watchpoint type |
|
1676 return true; |
|
1677 } |
|
1678 |
|
1679 return false; |
|
1680 } |
|
1681 |
|
1682 /** |
|
1683 * @param breakpoint |
|
1684 * @param oldValues |
|
1685 */ |
|
1686 protected void rollbackAttributes(ICBreakpoint breakpoint, IMarkerDelta oldValues) { |
|
1687 |
|
1688 try { |
|
1689 String new_condition = breakpoint.getCondition(); |
|
1690 if (new_condition == null) |
|
1691 new_condition = NULL_STRING; |
|
1692 String old_condition = (oldValues != null) ? oldValues.getAttribute(ICBreakpoint.CONDITION, NULL_STRING) : NULL_STRING; |
|
1693 if (!old_condition.equals(new_condition)) { |
|
1694 breakpoint.setCondition(old_condition); |
|
1695 } |
|
1696 else { |
|
1697 breakpoint.setCondition(NULL_STRING); |
|
1698 } |
|
1699 } catch (CoreException e) { |
|
1700 } |
|
1701 } |
|
1702 |
|
1703 /** |
|
1704 * Indicates if the back-end supports multiple threads for |
|
1705 * this type of breakpoint |
|
1706 * |
|
1707 * @param breakpoint |
|
1708 */ |
|
1709 protected boolean supportsThreads(ICBreakpoint breakpoint) { |
|
1710 |
|
1711 return !(breakpoint instanceof ICWatchpoint); |
|
1712 } |
|
1713 |
|
1714 } |
40 } |