~ubuntu-branches/debian/sid/eclipse-cdt/sid

« back to all changes in this revision

Viewing changes to dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java

  • Committer: Package Import Robot
  • Author(s): Jakub Adam
  • Date: 2011-10-06 21:15:04 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20111006211504-8dutmljjih0zikfv
Tags: 8.0.1-1
* New upstream release.
* Split the JNI packages into a separate architecture dependent
  package and made eclipse-cdt architecture independent.
* Install JNI libraries into multiarch aware location
* Bumped Standards-Version to 3.9.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************************
 
2
 * Copyright (c) 2006, 2011 Wind River Systems and others.
 
3
 * All rights reserved. This program and the accompanying materials
 
4
 * are made available under the terms of the Eclipse Public License v1.0
 
5
 * which accompanies this distribution, and is available at
 
6
 * http://www.eclipse.org/legal/epl-v10.html
 
7
 * 
 
8
 * Contributors:
 
9
 *     Wind River Systems - initial API and implementation
 
10
 *     Ericsson AB                - Modified for handling of multiple threads
 
11
 *******************************************************************************/
 
12
package org.eclipse.cdt.dsf.mi.service;
 
13
 
 
14
import java.util.HashMap;
 
15
import java.util.LinkedList;
 
16
import java.util.Map;
 
17
 
 
18
import org.eclipse.cdt.core.IAddress;
 
19
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
 
20
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
 
21
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
 
22
import org.eclipse.cdt.dsf.concurrent.Immutable;
 
23
import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
 
24
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
 
25
import org.eclipse.cdt.dsf.concurrent.Sequence;
 
26
import org.eclipse.cdt.dsf.concurrent.Sequence.Step;
 
27
import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
 
28
import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
 
29
import org.eclipse.cdt.dsf.datamodel.DMContexts;
 
30
import org.eclipse.cdt.dsf.datamodel.IDMContext;
 
31
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
 
32
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
 
33
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
 
34
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
 
35
import org.eclipse.cdt.dsf.debug.service.IBreakpointsExtension.IBreakpointHitDMEvent;
 
36
import org.eclipse.cdt.dsf.debug.service.ICachingService;
 
37
import org.eclipse.cdt.dsf.debug.service.IProcesses;
 
38
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
 
39
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
 
40
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
 
41
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
 
42
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
 
43
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
 
44
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
 
45
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
 
46
import org.eclipse.cdt.dsf.gdb.internal.service.command.events.MITracepointSelectedEvent;
 
47
import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext;
 
48
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
 
49
import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent;
 
50
import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent;
 
51
import org.eclipse.cdt.dsf.mi.service.command.events.MICatchpointHitEvent;
 
52
import org.eclipse.cdt.dsf.mi.service.command.events.MIErrorEvent;
 
53
import org.eclipse.cdt.dsf.mi.service.command.events.MIEvent;
 
54
import org.eclipse.cdt.dsf.mi.service.command.events.MIRunningEvent;
 
55
import org.eclipse.cdt.dsf.mi.service.command.events.MISharedLibEvent;
 
56
import org.eclipse.cdt.dsf.mi.service.command.events.MISignalEvent;
 
57
import org.eclipse.cdt.dsf.mi.service.command.events.MISteppingRangeEvent;
 
58
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
 
59
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadCreatedEvent;
 
60
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadExitEvent;
 
61
import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointTriggerEvent;
 
62
import org.eclipse.cdt.dsf.mi.service.command.output.CLIThreadInfo;
 
63
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
 
64
import org.eclipse.cdt.dsf.mi.service.command.output.MIThreadListIdsInfo;
 
65
import org.eclipse.cdt.dsf.service.AbstractDsfService;
 
66
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
 
67
import org.eclipse.cdt.dsf.service.DsfSession;
 
68
import org.eclipse.core.runtime.IStatus;
 
69
import org.eclipse.core.runtime.Status;
 
70
import org.eclipse.debug.core.DebugException;
 
71
import org.osgi.framework.BundleContext;
 
72
 
 
73
 
 
74
/**
 
75
 * 
 
76
 * <p>
 
77
 * Implementation note:
 
78
 * This class implements event handlers for the events that are generated by
 
79
 * this service itself.  When the event is dispatched, these handlers will
 
80
 * be called first, before any of the clients.  These handlers update the
 
81
 * service's internal state information to make them consistent with the
 
82
 * events being issued.  Doing this in the handlers as opposed to when
 
83
 * the events are generated, guarantees that the state of the service will
 
84
 * always be consistent with the events.
 
85
 * The purpose of this pattern is to allow clients that listen to service
 
86
 * events and track service state, to be perfectly in sync with the service
 
87
 * state.
 
88
 * @since 3.0
 
89
 */
 
90
public class MIRunControl extends AbstractDsfService implements IMIRunControl, ICachingService
 
91
{
 
92
        private static class MIExecutionDMC extends AbstractDMContext implements IMIExecutionDMContext
 
93
        {
 
94
                /**
 
95
                 * Integer ID that is used to identify the thread in the GDB/MI protocol.
 
96
                 */
 
97
                private final int fThreadId;
 
98
 
 
99
                /**
 
100
                 * Constructor for the context.  It should not be called directly by clients.
 
101
                 * Instead clients should call {@link MIRunControl#createMIExecutionContext(IContainerDMContext, int)}
 
102
                 * to create instances of this context based on the thread ID.
 
103
                 * <p/>
 
104
                 * Classes extending {@link MIRunControl} may also extend this class to include
 
105
                 * additional information in the context.
 
106
                 * 
 
107
                 * @param sessionId Session that this context belongs to.
 
108
                 * @param containerDmc The container that this context belongs to.
 
109
                 * @param threadId GDB/MI thread identifier.
 
110
                 */
 
111
                protected MIExecutionDMC(String sessionId, IContainerDMContext containerDmc, int threadId) {
 
112
                        super(sessionId, containerDmc != null ? new IDMContext[] { containerDmc } : new IDMContext[0]);
 
113
                        fThreadId = threadId;
 
114
                }
 
115
 
 
116
                /**
 
117
                 * Returns the GDB/MI thread identifier of this context.
 
118
                 * @return
 
119
                 */
 
120
                public int getThreadId(){
 
121
                        return fThreadId;
 
122
                }
 
123
 
 
124
                @Override
 
125
                public String toString() { return baseToString() + ".thread[" + fThreadId + "]"; }  //$NON-NLS-1$ //$NON-NLS-2$
 
126
 
 
127
                @Override
 
128
                public boolean equals(Object obj) {
 
129
                        return super.baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId == fThreadId;
 
130
                }
 
131
 
 
132
                @Override
 
133
                public int hashCode() { return super.baseHashCode() ^ fThreadId; }
 
134
        }
 
135
 
 
136
        @Immutable
 
137
        private static class ExecutionData implements IExecutionDMData2 {
 
138
                private final StateChangeReason fReason;
 
139
                private final String fDetails;
 
140
                ExecutionData(StateChangeReason reason, String details) {
 
141
                        fReason = reason;
 
142
                        fDetails = details;
 
143
                }
 
144
                public StateChangeReason getStateChangeReason() { return fReason; }
 
145
                public String getDetails() { return fDetails; }
 
146
        }
 
147
 
 
148
        /**
 
149
         * Base class for events generated by the MI Run Control service.  Most events
 
150
         * generated by the MI Run Control service are directly caused by some MI event.
 
151
         * Other services may need access to the extended MI data carried in the event.
 
152
         * 
 
153
         * @param <V> DMC that this event refers to
 
154
         * @param <T> MIInfo object that is the direct cause of this event
 
155
         * @see MIRunControl
 
156
         */
 
157
        @Immutable
 
158
        protected static class RunControlEvent<V extends IDMContext, T extends MIEvent<? extends IDMContext>> extends AbstractDMEvent<V>
 
159
        implements IDMEvent<V>, IMIDMEvent
 
160
        {
 
161
                final private T fMIInfo;
 
162
                public RunControlEvent(V dmc, T miInfo) {
 
163
                        super(dmc);
 
164
                        fMIInfo = miInfo;
 
165
                }
 
166
 
 
167
                public T getMIEvent() { return fMIInfo; }
 
168
        }
 
169
 
 
170
        /**
 
171
         * Indicates that the given thread has been suspended.
 
172
         */
 
173
        @Immutable
 
174
        protected static class SuspendedEvent extends RunControlEvent<IExecutionDMContext, MIStoppedEvent>
 
175
        implements ISuspendedDMEvent
 
176
        {
 
177
                SuspendedEvent(IExecutionDMContext ctx, MIStoppedEvent miInfo) {
 
178
                        super(ctx, miInfo);
 
179
                }
 
180
 
 
181
                public StateChangeReason getReason() {
 
182
                        if (getMIEvent() instanceof MICatchpointHitEvent) {     // must precede MIBreakpointHitEvent
 
183
                                return StateChangeReason.EVENT_BREAKPOINT;
 
184
                        } else if (getMIEvent() instanceof MITracepointSelectedEvent) { // must precede MIBreakpointHitEvent
 
185
                                return StateChangeReason.UNKNOWN;  // Don't display anything here, the details will take care of it
 
186
                        } else if (getMIEvent() instanceof MIBreakpointHitEvent) {
 
187
                                return StateChangeReason.BREAKPOINT;
 
188
                        } else if (getMIEvent() instanceof MISteppingRangeEvent) {
 
189
                                return StateChangeReason.STEP;
 
190
                        } else if (getMIEvent() instanceof MISharedLibEvent) {
 
191
                                return StateChangeReason.SHAREDLIB;
 
192
                        }else if (getMIEvent() instanceof MISignalEvent) {
 
193
                                return StateChangeReason.SIGNAL;
 
194
                        }else if (getMIEvent() instanceof MIWatchpointTriggerEvent) {
 
195
                                return StateChangeReason.WATCHPOINT;
 
196
                        }else if (getMIEvent() instanceof MIErrorEvent) {
 
197
                                return StateChangeReason.ERROR;
 
198
                        }else {
 
199
                                return StateChangeReason.USER_REQUEST;
 
200
                        }
 
201
                }
 
202
                
 
203
                /**
 
204
                 * @since 3.0
 
205
                 */
 
206
                public String getDetails() {
 
207
                        MIStoppedEvent event = getMIEvent();
 
208
                        if (event instanceof MICatchpointHitEvent) {    // must precede MIBreakpointHitEvent
 
209
                                return ((MICatchpointHitEvent)event).getReason();
 
210
                        } else if (event instanceof MITracepointSelectedEvent) {        // must precede MIBreakpointHitEvent
 
211
                                return ((MITracepointSelectedEvent)event).getReason();
 
212
                        } else if (event instanceof MISharedLibEvent) {
 
213
                                 return ((MISharedLibEvent)event).getLibrary();
 
214
                        } else if (event instanceof MISignalEvent) {
 
215
                                return ((MISignalEvent)event).getName() + ':' + ((MISignalEvent)event).getMeaning(); 
 
216
                        } else if (event instanceof MIWatchpointTriggerEvent) {
 
217
                                return ((MIWatchpointTriggerEvent)event).getExpression();
 
218
                        } else if (event instanceof MIErrorEvent) {
 
219
                                return ((MIErrorEvent)event).getMessage();
 
220
                        }
 
221
 
 
222
                        return null;
 
223
                }
 
224
        }
 
225
 
 
226
        /**
 
227
     * Indicates that the given thread has been suspended on a breakpoint.
 
228
         * @since 3.0
 
229
     */
 
230
    @Immutable
 
231
    protected static class BreakpointHitEvent extends SuspendedEvent
 
232
    implements IBreakpointHitDMEvent
 
233
    {
 
234
        final private IBreakpointDMContext[] fBreakpoints;
 
235
        
 
236
        BreakpointHitEvent(IExecutionDMContext ctx, MIBreakpointHitEvent miInfo, IBreakpointDMContext bpCtx) {
 
237
            super(ctx, miInfo);
 
238
            
 
239
            fBreakpoints = new IBreakpointDMContext[] { bpCtx };
 
240
        }
 
241
        
 
242
        public IBreakpointDMContext[] getBreakpoints() {
 
243
            return fBreakpoints;
 
244
        }
 
245
    }
 
246
 
 
247
        
 
248
        @Immutable
 
249
        protected static class ContainerSuspendedEvent extends SuspendedEvent
 
250
        implements IContainerSuspendedDMEvent
 
251
        {
 
252
                final IExecutionDMContext[] triggeringDmcs;
 
253
                ContainerSuspendedEvent(IContainerDMContext containerDmc, MIStoppedEvent miInfo, IExecutionDMContext triggeringDmc) {
 
254
                        super(containerDmc, miInfo);
 
255
                        this.triggeringDmcs = triggeringDmc != null
 
256
                        ? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0];
 
257
                }
 
258
 
 
259
                public IExecutionDMContext[] getTriggeringContexts() {
 
260
                        return triggeringDmcs;
 
261
                }
 
262
        }
 
263
 
 
264
   /**
 
265
     * Indicates that the given container has been suspended on a breakpoint.
 
266
     * @since 3.0
 
267
     */
 
268
    @Immutable
 
269
    protected static class ContainerBreakpointHitEvent extends ContainerSuspendedEvent
 
270
    implements IBreakpointHitDMEvent
 
271
    {
 
272
        final private IBreakpointDMContext[] fBreakpoints;
 
273
        
 
274
        ContainerBreakpointHitEvent(IContainerDMContext containerDmc, MIBreakpointHitEvent miInfo, IExecutionDMContext triggeringDmc, IBreakpointDMContext bpCtx) {
 
275
            super(containerDmc, miInfo, triggeringDmc);
 
276
            
 
277
            fBreakpoints = new IBreakpointDMContext[] { bpCtx };
 
278
        }
 
279
        
 
280
        public IBreakpointDMContext[] getBreakpoints() {
 
281
            return fBreakpoints;
 
282
        }
 
283
    }
 
284
 
 
285
        @Immutable
 
286
        protected static class ResumedEvent extends RunControlEvent<IExecutionDMContext, MIRunningEvent>
 
287
        implements IResumedDMEvent
 
288
        {
 
289
                ResumedEvent(IExecutionDMContext ctx, MIRunningEvent miInfo) {
 
290
                        super(ctx, miInfo);
 
291
                }
 
292
 
 
293
                public StateChangeReason getReason() {
 
294
                        switch(getMIEvent().getType()) {
 
295
                        case MIRunningEvent.CONTINUE:
 
296
                                return StateChangeReason.USER_REQUEST;
 
297
                        case MIRunningEvent.NEXT:
 
298
                        case MIRunningEvent.NEXTI:
 
299
                                return StateChangeReason.STEP;
 
300
                        case MIRunningEvent.STEP:
 
301
                        case MIRunningEvent.STEPI:
 
302
                                return StateChangeReason.STEP;
 
303
                        case MIRunningEvent.FINISH:
 
304
                                return StateChangeReason.STEP;
 
305
                        case MIRunningEvent.UNTIL:
 
306
                        case MIRunningEvent.RETURN:
 
307
                                break;
 
308
                        }
 
309
                        return StateChangeReason.UNKNOWN;
 
310
                }
 
311
        }
 
312
 
 
313
        @Immutable
 
314
        protected static class ContainerResumedEvent extends ResumedEvent
 
315
        implements IContainerResumedDMEvent
 
316
        {
 
317
                final IExecutionDMContext[] triggeringDmcs;
 
318
 
 
319
                ContainerResumedEvent(IContainerDMContext containerDmc, MIRunningEvent miInfo, IExecutionDMContext triggeringDmc) {
 
320
                        super(containerDmc, miInfo);
 
321
                        this.triggeringDmcs = triggeringDmc != null
 
322
                        ? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0];
 
323
                }
 
324
 
 
325
                public IExecutionDMContext[] getTriggeringContexts() {
 
326
                        return triggeringDmcs;
 
327
                }
 
328
        }
 
329
 
 
330
        @Immutable
 
331
        protected static class StartedDMEvent extends RunControlEvent<IExecutionDMContext,MIThreadCreatedEvent>
 
332
        implements IStartedDMEvent
 
333
        {
 
334
                StartedDMEvent(IMIExecutionDMContext executionDmc, MIThreadCreatedEvent miInfo) {
 
335
                        super(executionDmc, miInfo);
 
336
                }
 
337
        }
 
338
 
 
339
        @Immutable
 
340
        protected static class ExitedDMEvent extends RunControlEvent<IExecutionDMContext,MIThreadExitEvent>
 
341
        implements IExitedDMEvent
 
342
        {
 
343
                ExitedDMEvent(IMIExecutionDMContext executionDmc, MIThreadExitEvent miInfo) {
 
344
                        super(executionDmc, miInfo);
 
345
                }
 
346
        }
 
347
 
 
348
        private ICommandControlService fConnection;
 
349
        private CommandCache fMICommandCache;
 
350
        private CommandFactory fCommandFactory;
 
351
    
 
352
    // State flags
 
353
        private boolean fSuspended = true;
 
354
    private boolean fResumePending = false;
 
355
        private boolean fStepping = false;
 
356
        private boolean fTerminated = false;
 
357
        
 
358
        
 
359
        /**
 
360
         * What caused the state change. E.g., a signal was thrown.
 
361
         */
 
362
        private StateChangeReason fStateChangeReason;
 
363
 
 
364
        /**
 
365
         * Further detail on what caused the state change. E.g., the specific signal
 
366
         * that was throw was a SIGINT. The exact string comes from gdb in the mi
 
367
         * event. May be null, as not all types of state change have additional
 
368
         * detail of interest.
 
369
         */
 
370
        private String fStateChangeDetails;
 
371
        
 
372
        private IExecutionDMContext fStateChangeTriggeringContext;
 
373
        /** 
 
374
         * Indicates that the next MIRunning event should be silenced.
 
375
         */
 
376
        private boolean fDisableNextRunningEvent;
 
377
        /** 
 
378
         * Indicates that the next MISignal (MIStopped) event should be silenced.
 
379
         */
 
380
        private boolean fDisableNextSignalEvent;
 
381
        /** 
 
382
         * Stores the silenced MIStopped event in case we need to use it
 
383
         * for a failure.
 
384
         */
 
385
        private MIStoppedEvent fSilencedSignalEvent;
 
386
        
 
387
        private static final int FAKE_THREAD_ID = 0;
 
388
 
 
389
    public MIRunControl(DsfSession session) {
 
390
        super(session);
 
391
    }
 
392
    
 
393
    @Override
 
394
    public void initialize(final RequestMonitor rm) {
 
395
        super.initialize(
 
396
            new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
 
397
                @Override
 
398
                protected void handleSuccess() {
 
399
                    doInitialize(rm);
 
400
                }});
 
401
    }
 
402
 
 
403
    private void doInitialize(final RequestMonitor rm) {
 
404
        fConnection = getServicesTracker().getService(ICommandControlService.class);
 
405
        BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(fConnection, getExecutor(), 2);
 
406
        
 
407
        fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
 
408
                // This cache stores the result of a command when received; also, this cache
 
409
                // is manipulated when receiving events.  Currently, events are received after
 
410
                // three scheduling of the executor, while command results after only one.  This
 
411
                // can cause problems because command results might be processed before an event
 
412
                // that actually arrived before the command result.
 
413
                // To solve this, we use a bufferedCommandControl that will delay the command
 
414
                // result by two scheduling of the executor.
 
415
                // See bug 280461
 
416
        fMICommandCache = new CommandCache(getSession(), bufferedCommandControl);
 
417
        fMICommandCache.setContextAvailable(fConnection.getContext(), true);
 
418
        getSession().addServiceEventListener(this, null);
 
419
        rm.done();
 
420
    }
 
421
 
 
422
    @Override
 
423
    public void shutdown(final RequestMonitor rm) {
 
424
        getSession().removeServiceEventListener(this);
 
425
        fMICommandCache.reset();
 
426
        super.shutdown(rm);
 
427
    }
 
428
    
 
429
    public boolean isValid() { return true; }
 
430
    
 
431
    /** @since 2.0 */
 
432
    protected boolean isResumePending() { return fResumePending; }
 
433
    /** @since 2.0 */
 
434
    protected void setResumePending(boolean pending) { fResumePending = pending; }
 
435
    /** @since 2.0 */
 
436
    protected boolean isTerminated() { return fTerminated; }
 
437
    /** @since 2.0 */
 
438
    protected void setTerminated(boolean terminated) { fTerminated = terminated; }
 
439
    
 
440
    public CommandCache getCache() { return fMICommandCache; }
 
441
    /** @since 2.0 */
 
442
    protected ICommandControlService getConnection() { return fConnection; }
 
443
 
 
444
    public IMIExecutionDMContext createMIExecutionContext(IContainerDMContext container, int threadId) {
 
445
        return new MIExecutionDMC(getSession().getId(), container, threadId);
 
446
    }
 
447
    
 
448
    /**
 
449
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
450
     * @noreference This method is not intended to be referenced by clients.
 
451
     */
 
452
    @DsfServiceEventHandler
 
453
    public void eventDispatched(final MIRunningEvent e) {
 
454
        if (fDisableNextRunningEvent) {
 
455
                fDisableNextRunningEvent = false;
 
456
                // We don't broadcast this running event
 
457
                return;
 
458
        }
 
459
 
 
460
        IDMEvent<?> event = null;
 
461
        // Find the container context, which is used in multi-threaded debugging.
 
462
        IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class);
 
463
        if (containerDmc != null) {
 
464
            // Set the triggering context only if it's different than the container context.
 
465
            IExecutionDMContext triggeringCtx = !e.getDMContext().equals(containerDmc) ? e.getDMContext() : null;
 
466
            event = new ContainerResumedEvent(containerDmc, e, triggeringCtx);
 
467
        } else {
 
468
            event = new ResumedEvent(e.getDMContext(), e);
 
469
        }
 
470
        getSession().dispatchEvent(event, getProperties());
 
471
    }
 
472
 
 
473
    /**
 
474
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
475
     * @noreference This method is not intended to be referenced by clients.
 
476
     */
 
477
    @DsfServiceEventHandler
 
478
    public void eventDispatched(final MIStoppedEvent e) {
 
479
        if (fDisableNextSignalEvent && e instanceof MISignalEvent) {
 
480
                fDisableNextSignalEvent = false;
 
481
                fSilencedSignalEvent = e;
 
482
                // We don't broadcast this stopped event
 
483
                return;
 
484
        }
 
485
 
 
486
        MIBreakpointDMContext _bp = null;
 
487
        if (e instanceof MIBreakpointHitEvent) {
 
488
            int bpId = ((MIBreakpointHitEvent)e).getNumber();
 
489
            IBreakpointsTargetDMContext bpsTarget = DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class);
 
490
            if (bpsTarget != null && bpId >= 0) {
 
491
                _bp = new MIBreakpointDMContext(getSession().getId(), new IDMContext[] {bpsTarget}, bpId); 
 
492
            }
 
493
        }
 
494
        final MIBreakpointDMContext bp = _bp;
 
495
        
 
496
        IDMEvent<?> event = null;
 
497
        // Find the container context, which is used in multi-threaded debugging.
 
498
        final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class);
 
499
        if (containerDmc != null) {
 
500
            // Set the triggering context only if it's not the container context, since we are looking for a thread.
 
501
            IExecutionDMContext triggeringCtx = !e.getDMContext().equals(containerDmc) ? e.getDMContext() : null;
 
502
            if (triggeringCtx == null) {
 
503
                // Still no thread.  Let's ask the backend for one.
 
504
                // We need a proper thread id for the debug view to select the right thread
 
505
                // Bug 300096 comment #15 and Bug 302597
 
506
                                getConnection().queueCommand(
 
507
                                                fCommandFactory.createCLIThread(containerDmc),
 
508
                                                new DataRequestMonitor<CLIThreadInfo>(getExecutor(), null) {
 
509
                                                        @Override
 
510
                                                        protected void handleCompleted() {
 
511
                                                                IExecutionDMContext triggeringCtx2 = null;
 
512
                                                                if (isSuccess() && getData().getCurrentThread() != null) {
 
513
                                                                        triggeringCtx2 = createMIExecutionContext(containerDmc, getData().getCurrentThread());
 
514
                                                                }
 
515
                                                                IDMEvent<?> event2 = bp != null
 
516
                                                                    ? new ContainerBreakpointHitEvent(containerDmc, (MIBreakpointHitEvent)e, triggeringCtx2, bp)
 
517
                                                                    : new ContainerSuspendedEvent(containerDmc, e, triggeringCtx2);
 
518
                                                                getSession().dispatchEvent(event2, getProperties());
 
519
                                                        }
 
520
                                                });
 
521
                                return;
 
522
            }
 
523
            if (bp != null) {
 
524
                event = new ContainerBreakpointHitEvent(containerDmc, (MIBreakpointHitEvent)e, triggeringCtx, bp);
 
525
            } else {
 
526
                event = new ContainerSuspendedEvent(containerDmc, e, triggeringCtx);
 
527
            }
 
528
        } else {
 
529
            if (bp != null) {
 
530
                event = new BreakpointHitEvent(e.getDMContext(), (MIBreakpointHitEvent)e, bp);
 
531
            } else {
 
532
                event = new SuspendedEvent(e.getDMContext(), e);
 
533
            }
 
534
        }
 
535
        getSession().dispatchEvent(event, getProperties());
 
536
    }
 
537
 
 
538
    /**
 
539
     * Thread Created event handling
 
540
     * When a new thread is created - OOB Event fired ~"[New Thread 1077300144 (LWP 7973)]\n"
 
541
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
542
     * @noreference This method is not intended to be referenced by clients.
 
543
     */
 
544
    @DsfServiceEventHandler
 
545
    public void eventDispatched(final MIThreadCreatedEvent e) {
 
546
        IContainerDMContext containerDmc = e.getDMContext();
 
547
        IMIExecutionDMContext executionCtx = e.getStrId() != null ? createMIExecutionContext(containerDmc, e.getId()) : null;
 
548
        getSession().dispatchEvent(new StartedDMEvent(executionCtx, e), getProperties());
 
549
    }
 
550
 
 
551
    /**
 
552
     * Thread exit event handling
 
553
     * When a new thread is destroyed - OOB Event fired "
 
554
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
555
     * @noreference This method is not intended to be referenced by clients.
 
556
     */
 
557
    @DsfServiceEventHandler
 
558
    public void eventDispatched(final MIThreadExitEvent e) {
 
559
        IContainerDMContext containerDmc = e.getDMContext();
 
560
        IMIExecutionDMContext executionCtx = e.getStrId() != null ? createMIExecutionContext(containerDmc, e.getId()) : null;
 
561
        getSession().dispatchEvent(new ExitedDMEvent(executionCtx, e), getProperties());
 
562
    }
 
563
 
 
564
    /**
 
565
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
566
     * @noreference This method is not intended to be referenced by clients.
 
567
     */
 
568
    @DsfServiceEventHandler
 
569
    public void eventDispatched(ContainerResumedEvent e) {
 
570
        fSuspended = false;
 
571
        fResumePending = false;
 
572
        fStateChangeReason = e.getReason();
 
573
        fStateChangeDetails = null; // we have no details of interest for a resume
 
574
        fMICommandCache.setContextAvailable(e.getDMContext(), false);
 
575
        //fStateChangeTriggeringContext = e.getTriggeringContext();
 
576
        if (e.getReason().equals(StateChangeReason.STEP)) {
 
577
            fStepping = true;
 
578
        } else {
 
579
            fMICommandCache.reset();
 
580
        }
 
581
    }
 
582
 
 
583
    /**
 
584
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
585
     * @noreference This method is not intended to be referenced by clients.
 
586
     */
 
587
    @DsfServiceEventHandler
 
588
    public void eventDispatched(ContainerSuspendedEvent e) {
 
589
        fMICommandCache.setContextAvailable(e.getDMContext(), true);
 
590
        fMICommandCache.reset();
 
591
        fStateChangeReason = e.getReason();
 
592
        fStateChangeDetails = e.getDetails();
 
593
        fStateChangeTriggeringContext = e.getTriggeringContexts().length != 0
 
594
            ? e.getTriggeringContexts()[0] : null;
 
595
        fSuspended = true;
 
596
        fStepping = false;
 
597
        
 
598
        fResumePending = false;
 
599
    }
 
600
    
 
601
    /**
 
602
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
603
     * @noreference This method is not intended to be referenced by clients.
 
604
     * @since 1.1
 
605
     */
 
606
    @DsfServiceEventHandler
 
607
    public void eventDispatched(ICommandControlShutdownDMEvent e) {
 
608
        fTerminated = true;
 
609
        }
 
610
 
 
611
 
 
612
    /**
 
613
     * Event handler when New thread is created
 
614
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
615
     * @noreference This method is not intended to be referenced by clients.
 
616
     */
 
617
    @DsfServiceEventHandler
 
618
    public void eventDispatched(StartedDMEvent e) {
 
619
 
 
620
        }
 
621
 
 
622
    /**
 
623
     * @nooverride This method is not intended to be re-implemented or extended by clients.
 
624
     * @noreference This method is not intended to be referenced by clients.
 
625
     */
 
626
    @DsfServiceEventHandler
 
627
    public void eventDispatched(IExitedDMEvent e) {
 
628
        if (e.getDMContext() instanceof IContainerDMContext) {
 
629
                // When the process terminates, we should consider it as suspended
 
630
                // In fact, we did get a stopped event, but our processing of it
 
631
                // needs some cleaning up.  Until then, let's trigger of this event
 
632
                // Bug 342358
 
633
            fMICommandCache.setContextAvailable(e.getDMContext(), true);
 
634
            fMICommandCache.reset();
 
635
            
 
636
                fSuspended = true;
 
637
            fStepping = false;            
 
638
            fResumePending = false;
 
639
        } else {
 
640
                fMICommandCache.reset(e.getDMContext());
 
641
        }
 
642
    }
 
643
 
 
644
    ///////////////////////////////////////////////////////////////////////////
 
645
    // AbstractService
 
646
    @Override
 
647
    protected BundleContext getBundleContext() {
 
648
        return GdbPlugin.getBundleContext();
 
649
    }
 
650
    
 
651
    ///////////////////////////////////////////////////////////////////////////
 
652
    // IRunControl
 
653
        public void canResume(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
 
654
        rm.setData(doCanResume(context));
 
655
        rm.done();
 
656
        }
 
657
 
 
658
    /** @since 2.0 */
 
659
        protected boolean doCanResume(IExecutionDMContext context) {
 
660
            return !fTerminated && isSuspended(context) && !fResumePending;
 
661
        }
 
662
 
 
663
        public void canSuspend(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
 
664
        rm.setData(doCanSuspend(context));
 
665
        rm.done();
 
666
        }
 
667
        
 
668
    private boolean doCanSuspend(IExecutionDMContext context) {
 
669
        return !fTerminated && !isSuspended(context);
 
670
    }
 
671
 
 
672
        public boolean isSuspended(IExecutionDMContext context) {
 
673
                return !fTerminated && fSuspended;
 
674
        }
 
675
 
 
676
        public boolean isStepping(IExecutionDMContext context) {
 
677
        return !fTerminated && fStepping;
 
678
    }
 
679
 
 
680
        public void resume(final IExecutionDMContext context, final RequestMonitor rm) {
 
681
                assert context != null;
 
682
 
 
683
                if (doCanResume(context)) {
 
684
            ICommand<MIInfo> cmd = null;
 
685
            if(context instanceof IContainerDMContext) {
 
686
                cmd = fCommandFactory.createMIExecContinue(context);
 
687
            } else {
 
688
                        IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
 
689
                        if (dmc == null) {
 
690
                    rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
 
691
                    rm.done();
 
692
                    return;
 
693
                        }
 
694
                cmd = fCommandFactory.createMIExecContinue(dmc);//, new String[0]);
 
695
            }
 
696
            
 
697
            fResumePending = true;
 
698
            // Cygwin GDB will accept commands and execute them after the step
 
699
            // which is not what we want, so mark the target as unavailable
 
700
            // as soon as we send a resume command.
 
701
            fMICommandCache.setContextAvailable(context, false);
 
702
 
 
703
            fConnection.queueCommand(
 
704
                cmd,
 
705
                new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
 
706
                    @Override
 
707
                    protected void handleFailure() {
 
708
                            fResumePending = false;
 
709
                            fMICommandCache.setContextAvailable(context, true);
 
710
 
 
711
                        super.handleFailure();
 
712
                    }
 
713
                }
 
714
            );
 
715
        } else {
 
716
            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given context: " + context + ", is already running.", null)); //$NON-NLS-1$ //$NON-NLS-2$
 
717
            rm.done();
 
718
        }
 
719
        }
 
720
        
 
721
        public void suspend(IExecutionDMContext context, final RequestMonitor rm){
 
722
                assert context != null;
 
723
 
 
724
                if (doCanSuspend(context)) {
 
725
                        ICommand<MIInfo> cmd = null;
 
726
                        if(context instanceof IContainerDMContext){
 
727
                                cmd = fCommandFactory.createMIExecInterrupt(context);
 
728
                        }
 
729
                        else {
 
730
                                IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
 
731
                                if (dmc == null){
 
732
                            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
 
733
                            rm.done();
 
734
                            return;
 
735
                                }
 
736
                                cmd = fCommandFactory.createMIExecInterrupt(dmc);
 
737
                        }
 
738
            fConnection.queueCommand(cmd, new DataRequestMonitor<MIInfo>(getExecutor(), rm));
 
739
        } else {
 
740
            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Given context: " + context + ", is already suspended.", null)); //$NON-NLS-1$ //$NON-NLS-2$
 
741
            rm.done();
 
742
        }
 
743
    }
 
744
    
 
745
    public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm) {
 
746
        if (context instanceof IContainerDMContext) {
 
747
                rm.setData(false);
 
748
                rm.done();
 
749
                return;
 
750
        }
 
751
        canResume(context, rm);
 
752
    }
 
753
    
 
754
    public void step(final IExecutionDMContext context, StepType stepType, final RequestMonitor rm) {
 
755
        assert context != null;
 
756
 
 
757
        IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
 
758
                if (dmc == null){
 
759
            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
 
760
            rm.done();
 
761
            return;
 
762
                }
 
763
        
 
764
        if (!doCanResume(context)) {
 
765
            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$
 
766
            rm.done();
 
767
            return;
 
768
        }
 
769
 
 
770
        ICommand<MIInfo> cmd = null;
 
771
        switch(stepType) {
 
772
            case STEP_INTO:
 
773
                cmd = fCommandFactory.createMIExecStep(dmc, 1);
 
774
                break;
 
775
            case STEP_OVER:
 
776
                cmd = fCommandFactory.createMIExecNext(dmc);
 
777
                break;
 
778
            case STEP_RETURN:
 
779
                // The -exec-finish command operates on the selected stack frame, but here we always
 
780
                // want it to operate on the top stack frame.  So we manually create a top-frame
 
781
                // context to use with the MI command.
 
782
                // We get a local instance of the stack service because the stack service can be shut
 
783
                // down before the run control service is shut down.  So it is possible for the
 
784
                // getService() request below to return null.
 
785
                MIStack stackService = getServicesTracker().getService(MIStack.class);
 
786
                if (stackService != null) {
 
787
                    IFrameDMContext topFrameDmc = stackService.createFrameDMContext(dmc, 0);
 
788
                    cmd = fCommandFactory.createMIExecFinish(topFrameDmc);
 
789
                } else {
 
790
                    rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Cannot create context for command, stack service not available.", null)); //$NON-NLS-1$
 
791
                    rm.done();
 
792
                    return;
 
793
                }
 
794
                break;
 
795
            case INSTRUCTION_STEP_INTO:
 
796
                cmd = fCommandFactory.createMIExecStepInstruction(dmc, 1);
 
797
                break;
 
798
            case INSTRUCTION_STEP_OVER:
 
799
                cmd = fCommandFactory.createMIExecNextInstruction(dmc, 1);
 
800
                break;
 
801
            default:
 
802
                rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Given step type not supported", null)); //$NON-NLS-1$
 
803
                rm.done();
 
804
                return;
 
805
        }
 
806
        
 
807
        fResumePending = true;
 
808
        fStepping = true;
 
809
        fMICommandCache.setContextAvailable(context, false);
 
810
 
 
811
        fConnection.queueCommand(cmd, new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
 
812
                @Override
 
813
                public void handleFailure() {
 
814
                fResumePending = false;
 
815
                fStepping = false;
 
816
                fMICommandCache.setContextAvailable(context, true);
 
817
                
 
818
                super.handleFailure();
 
819
                }
 
820
        });
 
821
 
 
822
    }
 
823
 
 
824
    public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor<IExecutionDMContext[]> rm) {
 
825
                fMICommandCache.execute(
 
826
                                fCommandFactory.createMIThreadListIds(containerDmc),
 
827
                                new DataRequestMonitor<MIThreadListIdsInfo>(
 
828
                                                getExecutor(), rm) {
 
829
                                        @Override
 
830
                                        protected void handleSuccess() {
 
831
                                                rm.setData(makeExecutionDMCs(containerDmc, getData()));
 
832
                                                rm.done();
 
833
                                        }
 
834
                                });
 
835
    }
 
836
    
 
837
 
 
838
        private IExecutionDMContext[] makeExecutionDMCs(IContainerDMContext containerCtx, MIThreadListIdsInfo info) {
 
839
                if (info.getThreadIds().length == 0) {
 
840
                        // Main thread always exist even if it is not reported by GDB.
 
841
                        // So create thread-id = 0 when no thread is reported.
 
842
                        // This hack is necessary to prevent AbstractMIControl from issuing a thread-select
 
843
                        // because it doesn't work if the application was not compiled with pthread.
 
844
                        return new IMIExecutionDMContext[]{createMIExecutionContext(containerCtx, FAKE_THREAD_ID)};
 
845
                } else {
 
846
                        IExecutionDMContext[] executionDmcs = new IMIExecutionDMContext[info.getThreadIds().length];
 
847
                        for (int i = 0; i < info.getThreadIds().length; i++) {
 
848
                                executionDmcs[i] = createMIExecutionContext(containerCtx, info.getThreadIds()[i]);
 
849
                        }
 
850
                        return executionDmcs;
 
851
                }
 
852
        }
 
853
        
 
854
        public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm){
 
855
        if (dmc instanceof IContainerDMContext) {
 
856
            rm.setData( new ExecutionData(fStateChangeReason, fStateChangeDetails) );
 
857
        } else if (dmc instanceof IMIExecutionDMContext) {
 
858
                boolean thisThreadCausedStateChange = dmc.equals(fStateChangeTriggeringContext);
 
859
            StateChangeReason reason = thisThreadCausedStateChange ? fStateChangeReason : StateChangeReason.CONTAINER;
 
860
            String details = thisThreadCausedStateChange ? fStateChangeDetails : null;
 
861
                rm.setData(new ExecutionData(reason, details));
 
862
        } else {
 
863
            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Given context: " + dmc + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
 
864
        }
 
865
        rm.done();
 
866
    }
 
867
 
 
868
        /** @since 3.0 */
 
869
        protected void runToLocation(IExecutionDMContext context, String location, boolean skipBreakpoints, final RequestMonitor rm){
 
870
            // skipBreakpoints is not used at the moment. Implement later
 
871
            
 
872
        assert context != null;
 
873
 
 
874
        IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
 
875
                if (dmc == null){
 
876
            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
 
877
            rm.done();
 
878
            return;
 
879
                }
 
880
 
 
881
        if (doCanResume(dmc)) {
 
882
            fResumePending = true;
 
883
            fMICommandCache.setContextAvailable(dmc, false);
 
884
                fConnection.queueCommand(fCommandFactory.createMIExecUntil(dmc, location),
 
885
                                new DataRequestMonitor<MIInfo>(getExecutor(), rm));
 
886
        } else {
 
887
            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
 
888
                        "Cannot resume given DMC.", null)); //$NON-NLS-1$
 
889
            rm.done();
 
890
        }
 
891
        }
 
892
 
 
893
        /** @since 3.0 */
 
894
        protected void resumeAtLocation(IExecutionDMContext context, String location, RequestMonitor rm) {
 
895
                assert context != null;
 
896
 
 
897
                final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
 
898
                if (dmc == null){
 
899
                        rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Given context: " + context + " is not an thread execution context.", null)); //$NON-NLS-1$  //$NON-NLS-2$
 
900
                        rm.done();
 
901
                        return;
 
902
                }
 
903
 
 
904
                if (doCanResume(dmc)) {
 
905
                        fResumePending = true;
 
906
                        fMICommandCache.setContextAvailable(dmc, false);
 
907
                        fConnection.queueCommand(
 
908
                                        fCommandFactory.createCLIJump(dmc, location),
 
909
                                        new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
 
910
                                                @Override
 
911
                                                protected void handleFailure() {
 
912
                                                        fResumePending = false;
 
913
                                                        fMICommandCache.setContextAvailable(dmc, true);
 
914
 
 
915
                                                        super.handleFailure();
 
916
                                                }
 
917
                                        });
 
918
                } else {
 
919
                        rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
 
920
                                        "Cannot resume given DMC.", null)); //$NON-NLS-1$
 
921
                                        rm.done();
 
922
                }               
 
923
        }
 
924
 
 
925
        /* ******************************************************************************
 
926
         * Section to support operations even when the target is unavailable.
 
927
         *
 
928
         * Basically, we must make sure the container is suspended before making
 
929
         * certain operations (currently breakpoints).  If we don't, we must first 
 
930
         * suspend the container, then perform the specified operations,
 
931
         * and finally resume the container.
 
932
         * See http://bugs.eclipse.org/242943
 
933
         * and http://bugs.eclipse.org/282273
 
934
         * 
 
935
         * Note that for multi-process, the correct container must be suspended for the
 
936
         * breakpoint to be inserted on that container.  Not a big deal though, since
 
937
         * a breakpointDmc is mapped to a specific container.  Also, since we are in
 
938
         * all-stop mode here, it does not really matter what we stop, everything will
 
939
         * stop.
 
940
         * See http://bugs.eclipse.org/337893
 
941
         * 
 
942
         * ******************************************************************************/
 
943
 
 
944
        /**
 
945
         * Utility class to store the parameters of the executeWithTargetAvailable() operations.
 
946
         * @since 4.0
 
947
         */
 
948
        protected static class TargetAvailableOperationInfo {
 
949
                public IDMContext ctx;
 
950
                public Sequence.Step[] steps;
 
951
                public RequestMonitor rm;
 
952
                
 
953
                public TargetAvailableOperationInfo(IDMContext ctx, Step[] steps, RequestMonitor rm) {
 
954
                        super();
 
955
                        this.ctx = ctx;
 
956
                        this.steps = steps;
 
957
                        this.rm = rm;
 
958
                }
 
959
        };
 
960
 
 
961
        // Keep track of if the target was available or not when we started the operation
 
962
        private boolean fTargetAvailable;
 
963
        // The execution context that need to be available.
 
964
        private IExecutionDMContext fExecutionDmc;
 
965
        // Do we currently have an executeWithTargetAvailable() operation ongoing?
 
966
        private boolean fOngoingOperation;
 
967
        // Are we currently executing steps passed into executeWithTargetAvailable()?
 
968
        // This allows us to know if we can add more steps to execute or if we missed
 
969
        // our opportunity
 
970
        private boolean fCurrentlyExecutingSteps;
 
971
        
 
972
        // MultiRequestMonitor that allows us to track all the different steps we are
 
973
        // executing.  Once all steps are executed, we can complete this MultiRM and
 
974
        // allow the global sequence to continue.
 
975
        // Note that we couldn't use a CountingRequestMonitor because that type of RM
 
976
        // needs to know in advance how many subRms it will track; the MultiRM allows us
 
977
        // to receive more steps to execute continuously, and be able to upate the MultiRM.
 
978
        private MultiRequestMonitor<RequestMonitor> fExecuteQueuedOpsStepMonitor;
 
979
        // The number of batches of steps that are still being executing for potentially
 
980
        // concurrent executeWithTargetAvailable() operations.
 
981
        // Once this gets to zero, we know we have executed all the steps we were aware of
 
982
        // and we can complete the operation.
 
983
        private int fNumStepsStillExecuting;
 
984
        // Queue of executeWithTargetAvailable() operations that need to be processed.
 
985
        private LinkedList<TargetAvailableOperationInfo> fOperationsPending = new LinkedList<TargetAvailableOperationInfo>();
 
986
        
 
987
        /**
 
988
         * Returns whether the target is available to perform operations
 
989
         * @since 3.0
 
990
         */
 
991
        protected boolean isTargetAvailable() {
 
992
                return fTargetAvailable;
 
993
        }
 
994
 
 
995
        /** @since 4.0 */
 
996
        protected void setTargetAvailable(boolean available) {
 
997
                fTargetAvailable = available;
 
998
        }
 
999
        
 
1000
        /**
 
1001
         * Returns the execution context that needs to be suspended to perform the
 
1002
         * required operation.
 
1003
         * @since 3.0
 
1004
         */
 
1005
        protected IExecutionDMContext getContextToSuspend() {
 
1006
                return fExecutionDmc;
 
1007
        }
 
1008
 
 
1009
        /** @since 4.0 */
 
1010
        protected void setContextToSuspend(IExecutionDMContext context) {
 
1011
                fExecutionDmc = context;
 
1012
        }
 
1013
 
 
1014
        /** 
 
1015
         * Returns whether there is currently an ExecuteWithTargetAvailable() operation ongoing. 
 
1016
         * @since 4.0 
 
1017
         */
 
1018
        protected boolean isTargetAvailableOperationOngoing() {
 
1019
                return fOngoingOperation;
 
1020
        }
 
1021
        
 
1022
        /** @since 4.0 */
 
1023
        protected void setTargetAvailableOperationOngoing(boolean ongoing) {
 
1024
                fOngoingOperation = ongoing;
 
1025
        }
 
1026
        
 
1027
        /**
 
1028
         * Returns whether we are current in the process of executing the steps
 
1029
         * that were passed to ExecuteWithTargetAvailable().
 
1030
         * When this value is true, we can send more steps to be executed.
 
1031
         * @since 4.0 
 
1032
         */
 
1033
        protected boolean isCurrentlyExecutingSteps() {
 
1034
                return fCurrentlyExecutingSteps;
 
1035
        }
 
1036
 
 
1037
        /** @since 4.0 */
 
1038
        protected void setCurrentlyExecutingSteps(boolean executing) {
 
1039
                fCurrentlyExecutingSteps = executing;
 
1040
        }
 
1041
 
 
1042
        /**
 
1043
         * Returns the requestMonitor that will be run once all steps sent to
 
1044
         * ExecuteWithTargetAvailable() have been executed. 
 
1045
         * @since 4.0 
 
1046
         */
 
1047
        protected MultiRequestMonitor<RequestMonitor> getExecuteQueuedStepsRM() {
 
1048
                return fExecuteQueuedOpsStepMonitor;
 
1049
        }
 
1050
        
 
1051
        /** @since 4.0 */
 
1052
        protected void setExecuteQueuedStepsRM(MultiRequestMonitor<RequestMonitor> rm) {
 
1053
                fExecuteQueuedOpsStepMonitor = rm;
 
1054
        }
 
1055
 
 
1056
 
 
1057
        /**
 
1058
         * Returns the number of batches of steps sent to ExecuteWithTargetAvailable()
 
1059
         * that are still executing.  Once this number reaches zero, we can complete
 
1060
         * the overall ExecuteWithTargetAvailable() operation.
 
1061
         * @since 4.0 
 
1062
         */
 
1063
        protected int getNumStepsStillExecuting() {
 
1064
                return fNumStepsStillExecuting;
 
1065
        }
 
1066
 
 
1067
        /** @since 4.0 */
 
1068
        protected void setNumStepsStillExecuting(int num) {
 
1069
                fNumStepsStillExecuting = num;
 
1070
        }
 
1071
 
 
1072
        /**
 
1073
         * Returns the queue of executeWithTargetAvailable() operations that still need to be processed
 
1074
         * @since 4.0
 
1075
         */
 
1076
        protected LinkedList<TargetAvailableOperationInfo> getOperationsPending() {
 
1077
                return fOperationsPending;
 
1078
        }
 
1079
 
 
1080
        /**
 
1081
         * This method takes care of executing a batch of steps that were passed to
 
1082
         * ExecuteWithTargetAvailable().  The method is used to track the progress
 
1083
         * of all these batches of steps, so that we know exactly when all of them
 
1084
         * have been completed and the global sequence can be completed.
 
1085
         * @since 4.0
 
1086
         */
 
1087
        protected void executeSteps(final TargetAvailableOperationInfo info) {
 
1088
                fNumStepsStillExecuting++;
 
1089
                
 
1090
                // This RM propagates any error to the original rm of the actual steps.
 
1091
                // Even in case of errors for these steps, we want to continue the overall sequence
 
1092
                RequestMonitor stepsRm = new RequestMonitor(ImmediateExecutor.getInstance(), null) {
 
1093
                        @Override
 
1094
                        protected void handleCompleted() {
 
1095
                                info.rm.setStatus(getStatus());
 
1096
                                // It is important to call rm.done() right away.
 
1097
                                // This is because some other operation we are performing might be waiting
 
1098
                                // for this one to be done.  If we try to wait for the entire sequence to be
 
1099
                                // done, then we will never finish because one monitor will never show as
 
1100
                                // done, waiting for the second one.
 
1101
                                info.rm.done();
 
1102
 
 
1103
                                fExecuteQueuedOpsStepMonitor.requestMonitorDone(this);
 
1104
                                fNumStepsStillExecuting--;
 
1105
                                if (fNumStepsStillExecuting == 0) {
 
1106
                                        fExecuteQueuedOpsStepMonitor.doneAdding();
 
1107
                                }
 
1108
                        }
 
1109
                };
 
1110
 
 
1111
                fExecuteQueuedOpsStepMonitor.add(stepsRm);
 
1112
 
 
1113
                getExecutor().execute(new Sequence(getExecutor(), stepsRm) {
 
1114
                        @Override public Step[] getSteps() { return info.steps; }
 
1115
                });     
 
1116
        }
 
1117
        
 
1118
        /**
 
1119
         * @since 3.0
 
1120
         */
 
1121
        public void executeWithTargetAvailable(IDMContext ctx, final Sequence.Step[] steps, final RequestMonitor rm) {
 
1122
                if (!fOngoingOperation) {
 
1123
                        // We are the first operation of this kind currently requested
 
1124
                        // so we need to start the sequence
 
1125
                        fOngoingOperation = true;
 
1126
 
 
1127
                        // We always go through our queue, even if we only have a single call to this method
 
1128
                        fOperationsPending.add(new TargetAvailableOperationInfo(ctx, steps, rm));
 
1129
                        
 
1130
                        // Steps that need to be executed to perform the operation
 
1131
                        final Step[] sequenceSteps = new Step[] {
 
1132
                                        new IsTargetAvailableStep(ctx),
 
1133
                                        new MakeTargetAvailableStep(),
 
1134
                                        new ExecuteQueuedOperationsStep(),
 
1135
                                        new RestoreTargetStateStep(),
 
1136
                        };
 
1137
                        
 
1138
                        // Once all the sequence is completed, we need to see if we have received
 
1139
                        // another request that we now need to process
 
1140
                        RequestMonitor sequenceCompletedRm = new RequestMonitor(getExecutor(), null) {
 
1141
                                @Override
 
1142
                                protected void handleSuccess() {
 
1143
                                         fOngoingOperation = false;
 
1144
                                         
 
1145
                                         if (fOperationsPending.size() > 0) {
 
1146
                                                 // Darn, more operations came in.  Trigger their processing
 
1147
                                                 // by calling executeWithTargetAvailable() on the last one
 
1148
                                                 TargetAvailableOperationInfo info = fOperationsPending.removeLast();
 
1149
                                                 executeWithTargetAvailable(info.ctx, info.steps, info.rm);
 
1150
                                         }
 
1151
                                         // no other rm.done() needs to be called, they have all been handled already
 
1152
                                }
 
1153
                                @Override
 
1154
                                protected void handleFailure() {
 
1155
                                        // If the sequence failed, we have to give up on the operation(s).
 
1156
                                        // If we don't, we risk an infinite loop where we try, over and over
 
1157
                                        // to perform an operation that keeps on failing.
 
1158
                                        fOngoingOperation = false;
 
1159
                                        
 
1160
                                        // Complete each rm of the cancelled operations
 
1161
                                        while (fOperationsPending.size() > 0) {
 
1162
                                                RequestMonitor rm = fOperationsPending.poll().rm;
 
1163
                                                rm.setStatus(getStatus());
 
1164
                                                rm.done();
 
1165
                                        }
 
1166
 
 
1167
                                        super.handleFailure();
 
1168
                                }
 
1169
                        };
 
1170
                        
 
1171
                        getExecutor().execute(new Sequence(getExecutor(), sequenceCompletedRm) {
 
1172
                                @Override public Step[] getSteps() { return sequenceSteps; }
 
1173
                        });
 
1174
                } else {
 
1175
                        // We are currently already executing such an operation
 
1176
                        // If we are still in the process of executing steps, let's include this new set of steps.
 
1177
                        // This is important because some steps may depend on these new ones.
 
1178
                        if (fCurrentlyExecutingSteps) {
 
1179
                                executeSteps(new TargetAvailableOperationInfo(ctx, steps, rm));
 
1180
                        } else {
 
1181
                                // Too late to execute the new steps, so queue them for later
 
1182
                                fOperationsPending.add(new TargetAvailableOperationInfo(ctx, steps, rm));
 
1183
                        }
 
1184
                }
 
1185
        }
 
1186
        
 
1187
        
 
1188
        /**
 
1189
         * This part of the sequence verifies if the execution context of interest
 
1190
         * is suspended or not.
 
1191
         * @since 3.0
 
1192
         */
 
1193
        protected class IsTargetAvailableStep extends Sequence.Step {
 
1194
                final IDMContext fCtx;
 
1195
                
 
1196
                public IsTargetAvailableStep(IDMContext ctx) {
 
1197
                        fCtx = ctx;
 
1198
                }
 
1199
                
 
1200
                @Override
 
1201
                public void execute(final RequestMonitor rm) {
 
1202
                        fExecutionDmc = DMContexts.getAncestorOfType(fCtx, IMIContainerDMContext.class);
 
1203
                        if (fExecutionDmc != null) {
 
1204
                                fTargetAvailable = isSuspended(fExecutionDmc);
 
1205
                                rm.done();
 
1206
                                return;
 
1207
                        }
 
1208
 
 
1209
                        ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(fCtx, ICommandControlDMContext.class);
 
1210
                        IProcesses processControl = getServicesTracker().getService(IProcesses.class);
 
1211
                        processControl.getProcessesBeingDebugged(
 
1212
                                        controlDmc,
 
1213
                                        new DataRequestMonitor<IDMContext[]>(getExecutor(), rm) {
 
1214
                                                @Override
 
1215
                                                protected void handleSuccess() {
 
1216
                                                        assert getData() != null;
 
1217
                                                        
 
1218
                                                        if (getData().length == 0) {
 
1219
                                                                // Happens at startup, starting with GDB 7.0.
 
1220
                                                                // This means the target is available
 
1221
                                                                fTargetAvailable = true;
 
1222
                                                        } else {
 
1223
                                                                // In all-stop, if any process is suspended, then all of them are suspended
 
1224
                                                                // so we only need to check the first process.
 
1225
                                                                fExecutionDmc = (IExecutionDMContext)(getData()[0]);
 
1226
                                                                fTargetAvailable = isSuspended(fExecutionDmc);
 
1227
                                                        }
 
1228
                                                        rm.done();
 
1229
                                                }
 
1230
                                        });
 
1231
                }
 
1232
        };
 
1233
 
 
1234
        /**
 
1235
         * If the execution context of interest is not suspended, this step
 
1236
         * will interrupt it.
 
1237
         * @since 3.0
 
1238
         */
 
1239
        protected class MakeTargetAvailableStep extends Sequence.Step {
 
1240
                @Override
 
1241
                public void execute(final RequestMonitor rm) {
 
1242
                        if (!isTargetAvailable()) {
 
1243
                                assert fDisableNextRunningEvent == false;
 
1244
                                assert fDisableNextSignalEvent == false;
 
1245
                                
 
1246
                                // Don't broadcast the coming stopped signal event
 
1247
                                fDisableNextSignalEvent = true;
 
1248
                                suspend(getContextToSuspend(), 
 
1249
                                                new RequestMonitor(getExecutor(), rm) {
 
1250
                                        @Override
 
1251
                                        protected void handleFailure() {
 
1252
                                                // We weren't able to suspend, so abort the operation
 
1253
                                                fDisableNextSignalEvent = false;
 
1254
                                                super.handleFailure();
 
1255
                                        };
 
1256
                                });
 
1257
                        } else {
 
1258
                                rm.done();
 
1259
                        }
 
1260
                }
 
1261
                @Override
 
1262
                public void rollBack(RequestMonitor rm) {
 
1263
                    Sequence.Step restoreStep = new RestoreTargetStateStep();
 
1264
                    restoreStep.execute(rm);
 
1265
                }
 
1266
        };
 
1267
 
 
1268
        /**
 
1269
         * This step of the sequence takes care of executing all the steps that
 
1270
         * were passed to ExecuteWithTargetAvailable().
 
1271
         * @since 4.0
 
1272
         */
 
1273
        protected class ExecuteQueuedOperationsStep extends Sequence.Step {
 
1274
                @Override
 
1275
                public void execute(final RequestMonitor rm) {
 
1276
                        fCurrentlyExecutingSteps = true;
 
1277
                        
 
1278
                        // It is important to use an ImmediateExecutor for this RM, to make sure we don't risk getting a new
 
1279
                        // call to ExecuteWithTargetAvailable() when we just finished executing the steps.
 
1280
                        fExecuteQueuedOpsStepMonitor = new MultiRequestMonitor<RequestMonitor>(ImmediateExecutor.getInstance(), rm) {
 
1281
                                @Override
 
1282
                                protected void handleCompleted() {
 
1283
                                        assert fOperationsPending.size() == 0;
 
1284
                                        
 
1285
                                        // We don't handle errors here.  Instead, we have already propagated any
 
1286
                                        // errors to each rm for each set of steps
 
1287
                                        
 
1288
                                        fCurrentlyExecutingSteps = false;
 
1289
                                        // Continue the sequence
 
1290
                                        rm.done();
 
1291
                                }
 
1292
                        };
 
1293
                        // Tell the RM that we need to confirm when we are done adding sub-rms
 
1294
                        fExecuteQueuedOpsStepMonitor.requireDoneAdding();
 
1295
                                                
 
1296
                        // All pending operations are independent of each other so we can
 
1297
                        // run them concurrently.
 
1298
                        while (fOperationsPending.size() > 0) {
 
1299
                                executeSteps(fOperationsPending.poll());                                
 
1300
                        }
 
1301
                }
 
1302
        };
 
1303
        
 
1304
        /**
 
1305
         * If the sequence had to interrupt the execution context of interest,
 
1306
         * this step will resume it again to reach the same state as when we started.
 
1307
         * @since 3.0
 
1308
         */
 
1309
        protected class RestoreTargetStateStep extends Sequence.Step {
 
1310
                @Override
 
1311
                public void execute(final RequestMonitor rm) {
 
1312
                        if (!isTargetAvailable()) {
 
1313
                                assert fDisableNextRunningEvent == false;
 
1314
                                fDisableNextRunningEvent = true;
 
1315
                                
 
1316
                                // Can't use the resume() call because we 'silently' stopped
 
1317
                                // so resume() will not know we are actually stopped
 
1318
                                fConnection.queueCommand(
 
1319
                                                fCommandFactory.createMIExecContinue(getContextToSuspend()),
 
1320
                                                new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
 
1321
                                                        @Override
 
1322
                                                        protected void handleSuccess() {
 
1323
                                                                fSilencedSignalEvent = null;
 
1324
                                                                super.handleSuccess();
 
1325
                                                        }
 
1326
 
 
1327
                                                        @Override
 
1328
                                                        protected void handleFailure() {
 
1329
                                                                // Darn, we're unable to restart the target.  Must cleanup!
 
1330
                                                                fDisableNextRunningEvent = false;
 
1331
                                                                
 
1332
                                                                // We must also sent the Stopped event that we had kept silent
 
1333
                                                                if (fSilencedSignalEvent != null) {
 
1334
                                                                        eventDispatched(fSilencedSignalEvent);
 
1335
                                                                        fSilencedSignalEvent = null;
 
1336
                                                                } else {
 
1337
                                                                        // Maybe the stopped event didn't arrive yet.
 
1338
                                                                        // We don't want to silence it anymore
 
1339
                                                                        fDisableNextSignalEvent = false;
 
1340
                                                                }
 
1341
 
 
1342
                                                                super.handleFailure();
 
1343
                                                        }
 
1344
                                                });
 
1345
                        } else {
 
1346
                                // We didn't suspend the container, so we don't need to resume it
 
1347
                                rm.done();
 
1348
                        }
 
1349
                }
 
1350
         };
 
1351
 
 
1352
         /* ******************************************************************************
 
1353
          * End of section to support operations even when the target is unavailable.
 
1354
          * ******************************************************************************/
 
1355
 
 
1356
        /**
 
1357
         * {@inheritDoc}
 
1358
     * @since 1.1
 
1359
     */
 
1360
        public void flushCache(IDMContext context) {
 
1361
                fMICommandCache.reset(context);         
 
1362
        }
 
1363
 
 
1364
        private void moveToLocation(final IExecutionDMContext context,
 
1365
                        final String location, final Map<String, Object> bpAttributes,
 
1366
                        final RequestMonitor rm) {
 
1367
 
 
1368
                // first create a temporary breakpoint to stop the execution at
 
1369
                // the location we are about to jump to
 
1370
                IBreakpoints bpService = getServicesTracker().getService(IBreakpoints.class);
 
1371
                IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(context, IBreakpointsTargetDMContext.class);
 
1372
                if (bpService != null && bpDmc != null) {
 
1373
                        bpService.insertBreakpoint(bpDmc, bpAttributes,
 
1374
                                        new DataRequestMonitor<IBreakpointDMContext>(getExecutor(),rm) {
 
1375
                                                @Override
 
1376
                                                protected void handleSuccess() {
 
1377
                                                        // Now resume at the proper location
 
1378
                                                        resumeAtLocation(context, location, rm);
 
1379
                                                }
 
1380
                                        });
 
1381
                } else {
 
1382
                        rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
 
1383
                                        IDsfStatusConstants.NOT_SUPPORTED,
 
1384
                                        "Unable to set breakpoint", null)); //$NON-NLS-1$
 
1385
                        rm.done();
 
1386
                }
 
1387
        }
 
1388
 
 
1389
        /* (non-Javadoc)
 
1390
         * @see org.eclipse.cdt.dsf.debug.service.IRunControl2#canRunToLine(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, java.lang.String, int, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
 
1391
         */
 
1392
        /**
 
1393
         * @since 3.0
 
1394
         */
 
1395
        public void canRunToLine(IExecutionDMContext context, String sourceFile,
 
1396
                        int lineNumber, DataRequestMonitor<Boolean> rm) {
 
1397
                canResume(context, rm);
 
1398
        }
 
1399
 
 
1400
        /* (non-Javadoc)
 
1401
         * @see org.eclipse.cdt.dsf.debug.service.IRunControl2#runToLine(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, java.lang.String, int, boolean, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
 
1402
         */
 
1403
        /**
 
1404
         * @since 3.0
 
1405
         */
 
1406
        public void runToLine(IExecutionDMContext context, String sourceFile,
 
1407
                        int lineNumber, boolean skipBreakpoints, RequestMonitor rm) {
 
1408
                
 
1409
                // Hack around a MinGW bug; see 196154
 
1410
                sourceFile = MIBreakpointsManager.adjustDebuggerPath(sourceFile);
 
1411
                
 
1412
                runToLocation(context, sourceFile + ":" + Integer.toString(lineNumber), skipBreakpoints, rm); //$NON-NLS-1$
 
1413
        }
 
1414
 
 
1415
        /* (non-Javadoc)
 
1416
         * @see org.eclipse.cdt.dsf.debug.service.IRunControl2#canRunToAddress(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.core.IAddress, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
 
1417
         */
 
1418
        /**
 
1419
         * @since 3.0
 
1420
         */
 
1421
        public void canRunToAddress(IExecutionDMContext context, IAddress address,
 
1422
                        DataRequestMonitor<Boolean> rm) {
 
1423
                canResume(context, rm);
 
1424
        }
 
1425
 
 
1426
        /* (non-Javadoc)
 
1427
         * @see org.eclipse.cdt.dsf.debug.service.IRunControl2#runToAddress(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.core.IAddress, boolean, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
 
1428
         */
 
1429
        /**
 
1430
         * @since 3.0
 
1431
         */
 
1432
        public void runToAddress(IExecutionDMContext context, IAddress address,
 
1433
                        boolean skipBreakpoints, RequestMonitor rm) {
 
1434
                runToLocation(context, "*0x" + address.toString(16), skipBreakpoints, rm); //$NON-NLS-1$
 
1435
        }
 
1436
 
 
1437
        /* (non-Javadoc)
 
1438
         * @see org.eclipse.cdt.dsf.debug.service.IRunControl2#canMoveToLine(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, java.lang.String, int, boolean, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
 
1439
         */
 
1440
        /**
 
1441
         * @since 3.0
 
1442
         */
 
1443
        public void canMoveToLine(IExecutionDMContext context, String sourceFile,
 
1444
                        int lineNumber, boolean resume, DataRequestMonitor<Boolean> rm) {
 
1445
                canResume(context, rm);
 
1446
        }
 
1447
 
 
1448
        /* (non-Javadoc)
 
1449
         * @see org.eclipse.cdt.dsf.debug.service.IRunControl2#moveToLine(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, java.lang.String, int, boolean, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
 
1450
         */
 
1451
        /**
 
1452
         * @since 3.0
 
1453
         */
 
1454
        public void moveToLine(IExecutionDMContext context, String sourceFile,
 
1455
                        int lineNumber, boolean resume, RequestMonitor rm) {
 
1456
                IMIExecutionDMContext threadExecDmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
 
1457
                if (threadExecDmc == null) {
 
1458
            rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Invalid thread context", null)); //$NON-NLS-1$
 
1459
            rm.done();                          
 
1460
                }
 
1461
                else
 
1462
                {               
 
1463
                        String location = sourceFile + ":" + lineNumber; //$NON-NLS-1$
 
1464
                        if (resume)
 
1465
                                resumeAtLocation(context, location, rm);
 
1466
                        else {
 
1467
                                // Create the breakpoint attributes
 
1468
                                Map<String,Object> attr = new HashMap<String,Object>();
 
1469
                                attr.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.BREAKPOINT);
 
1470
                                attr.put(MIBreakpoints.FILE_NAME, sourceFile);
 
1471
                                attr.put(MIBreakpoints.LINE_NUMBER, lineNumber);
 
1472
                                attr.put(MIBreakpointDMData.IS_TEMPORARY, true);
 
1473
                                attr.put(MIBreakpointDMData.THREAD_ID, Integer.toString(threadExecDmc.getThreadId()));
 
1474
                                
 
1475
                                // Now do the operation
 
1476
                                moveToLocation(context, location, attr, rm);
 
1477
                        }
 
1478
                }
 
1479
        }
 
1480
 
 
1481
        /* (non-Javadoc)
 
1482
         * @see org.eclipse.cdt.dsf.debug.service.IRunControl2#canMoveToAddress(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.core.IAddress, boolean, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
 
1483
         */
 
1484
        /**
 
1485
         * @since 3.0
 
1486
         */
 
1487
        public void canMoveToAddress(IExecutionDMContext context, IAddress address,
 
1488
                        boolean resume, DataRequestMonitor<Boolean> rm) {
 
1489
                canResume(context, rm);
 
1490
        }
 
1491
 
 
1492
        /* (non-Javadoc)
 
1493
         * @see org.eclipse.cdt.dsf.debug.service.IRunControl2#moveToAddress(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.core.IAddress, boolean, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
 
1494
         */
 
1495
        /**
 
1496
         * @since 3.0
 
1497
         */
 
1498
        public void moveToAddress(IExecutionDMContext context, IAddress address,
 
1499
                        boolean resume, RequestMonitor rm) {
 
1500
                IMIExecutionDMContext threadExecDmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
 
1501
                if (threadExecDmc == null) {
 
1502
                        rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Invalid thread context", null)); //$NON-NLS-1$
 
1503
                        rm.done();                              
 
1504
                }
 
1505
                else
 
1506
                {
 
1507
                        String location = "*0x" + address.toString(16); //$NON-NLS-1$
 
1508
                        if (resume)
 
1509
                                resumeAtLocation(context, location, rm);
 
1510
                        else {
 
1511
                                // Create the breakpoint attributes
 
1512
                                Map<String,Object> attr = new HashMap<String,Object>();
 
1513
                                attr.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.BREAKPOINT);
 
1514
                                attr.put(MIBreakpoints.ADDRESS, "0x" + address.toString(16)); //$NON-NLS-1$
 
1515
                                attr.put(MIBreakpointDMData.IS_TEMPORARY, true);
 
1516
                                attr.put(MIBreakpointDMData.THREAD_ID,  Integer.toString(threadExecDmc.getThreadId()));
 
1517
 
 
1518
                                // Now do the operation
 
1519
                                moveToLocation(context, location, attr, rm);
 
1520
                        }
 
1521
                }
 
1522
        }
 
1523
 
 
1524
        /** @since 4.0 */
 
1525
        public IRunMode getRunMode() {
 
1526
                return MIRunMode.ALL_STOP;
 
1527
        }
 
1528
        
 
1529
        /** @since 4.0 */
 
1530
        public boolean isTargetAcceptingCommands() {
 
1531
                // For all-stop mode:
 
1532
                // 1- if GDB is not terminated and
 
1533
                // 2- if execution is suspended and 
 
1534
                // 3- if we didn't just send a resume/stop command, then 
 
1535
                // we know GDB is accepting commands
 
1536
                return !fTerminated && fSuspended && !fResumePending;
 
1537
        }
 
1538
}