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
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;
14
import java.util.HashMap;
15
import java.util.LinkedList;
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;
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
90
public class MIRunControl extends AbstractDsfService implements IMIRunControl, ICachingService
92
private static class MIExecutionDMC extends AbstractDMContext implements IMIExecutionDMContext
95
* Integer ID that is used to identify the thread in the GDB/MI protocol.
97
private final int fThreadId;
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.
104
* Classes extending {@link MIRunControl} may also extend this class to include
105
* additional information in the context.
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.
111
protected MIExecutionDMC(String sessionId, IContainerDMContext containerDmc, int threadId) {
112
super(sessionId, containerDmc != null ? new IDMContext[] { containerDmc } : new IDMContext[0]);
113
fThreadId = threadId;
117
* Returns the GDB/MI thread identifier of this context.
120
public int getThreadId(){
125
public String toString() { return baseToString() + ".thread[" + fThreadId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
128
public boolean equals(Object obj) {
129
return super.baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId == fThreadId;
133
public int hashCode() { return super.baseHashCode() ^ fThreadId; }
137
private static class ExecutionData implements IExecutionDMData2 {
138
private final StateChangeReason fReason;
139
private final String fDetails;
140
ExecutionData(StateChangeReason reason, String details) {
144
public StateChangeReason getStateChangeReason() { return fReason; }
145
public String getDetails() { return fDetails; }
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.
153
* @param <V> DMC that this event refers to
154
* @param <T> MIInfo object that is the direct cause of this event
158
protected static class RunControlEvent<V extends IDMContext, T extends MIEvent<? extends IDMContext>> extends AbstractDMEvent<V>
159
implements IDMEvent<V>, IMIDMEvent
161
final private T fMIInfo;
162
public RunControlEvent(V dmc, T miInfo) {
167
public T getMIEvent() { return fMIInfo; }
171
* Indicates that the given thread has been suspended.
174
protected static class SuspendedEvent extends RunControlEvent<IExecutionDMContext, MIStoppedEvent>
175
implements ISuspendedDMEvent
177
SuspendedEvent(IExecutionDMContext ctx, MIStoppedEvent miInfo) {
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;
199
return StateChangeReason.USER_REQUEST;
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();
227
* Indicates that the given thread has been suspended on a breakpoint.
231
protected static class BreakpointHitEvent extends SuspendedEvent
232
implements IBreakpointHitDMEvent
234
final private IBreakpointDMContext[] fBreakpoints;
236
BreakpointHitEvent(IExecutionDMContext ctx, MIBreakpointHitEvent miInfo, IBreakpointDMContext bpCtx) {
239
fBreakpoints = new IBreakpointDMContext[] { bpCtx };
242
public IBreakpointDMContext[] getBreakpoints() {
249
protected static class ContainerSuspendedEvent extends SuspendedEvent
250
implements IContainerSuspendedDMEvent
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];
259
public IExecutionDMContext[] getTriggeringContexts() {
260
return triggeringDmcs;
265
* Indicates that the given container has been suspended on a breakpoint.
269
protected static class ContainerBreakpointHitEvent extends ContainerSuspendedEvent
270
implements IBreakpointHitDMEvent
272
final private IBreakpointDMContext[] fBreakpoints;
274
ContainerBreakpointHitEvent(IContainerDMContext containerDmc, MIBreakpointHitEvent miInfo, IExecutionDMContext triggeringDmc, IBreakpointDMContext bpCtx) {
275
super(containerDmc, miInfo, triggeringDmc);
277
fBreakpoints = new IBreakpointDMContext[] { bpCtx };
280
public IBreakpointDMContext[] getBreakpoints() {
286
protected static class ResumedEvent extends RunControlEvent<IExecutionDMContext, MIRunningEvent>
287
implements IResumedDMEvent
289
ResumedEvent(IExecutionDMContext ctx, MIRunningEvent miInfo) {
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:
309
return StateChangeReason.UNKNOWN;
314
protected static class ContainerResumedEvent extends ResumedEvent
315
implements IContainerResumedDMEvent
317
final IExecutionDMContext[] triggeringDmcs;
319
ContainerResumedEvent(IContainerDMContext containerDmc, MIRunningEvent miInfo, IExecutionDMContext triggeringDmc) {
320
super(containerDmc, miInfo);
321
this.triggeringDmcs = triggeringDmc != null
322
? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0];
325
public IExecutionDMContext[] getTriggeringContexts() {
326
return triggeringDmcs;
331
protected static class StartedDMEvent extends RunControlEvent<IExecutionDMContext,MIThreadCreatedEvent>
332
implements IStartedDMEvent
334
StartedDMEvent(IMIExecutionDMContext executionDmc, MIThreadCreatedEvent miInfo) {
335
super(executionDmc, miInfo);
340
protected static class ExitedDMEvent extends RunControlEvent<IExecutionDMContext,MIThreadExitEvent>
341
implements IExitedDMEvent
343
ExitedDMEvent(IMIExecutionDMContext executionDmc, MIThreadExitEvent miInfo) {
344
super(executionDmc, miInfo);
348
private ICommandControlService fConnection;
349
private CommandCache fMICommandCache;
350
private CommandFactory fCommandFactory;
353
private boolean fSuspended = true;
354
private boolean fResumePending = false;
355
private boolean fStepping = false;
356
private boolean fTerminated = false;
360
* What caused the state change. E.g., a signal was thrown.
362
private StateChangeReason fStateChangeReason;
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.
370
private String fStateChangeDetails;
372
private IExecutionDMContext fStateChangeTriggeringContext;
374
* Indicates that the next MIRunning event should be silenced.
376
private boolean fDisableNextRunningEvent;
378
* Indicates that the next MISignal (MIStopped) event should be silenced.
380
private boolean fDisableNextSignalEvent;
382
* Stores the silenced MIStopped event in case we need to use it
385
private MIStoppedEvent fSilencedSignalEvent;
387
private static final int FAKE_THREAD_ID = 0;
389
public MIRunControl(DsfSession session) {
394
public void initialize(final RequestMonitor rm) {
396
new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
398
protected void handleSuccess() {
403
private void doInitialize(final RequestMonitor rm) {
404
fConnection = getServicesTracker().getService(ICommandControlService.class);
405
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(fConnection, getExecutor(), 2);
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.
416
fMICommandCache = new CommandCache(getSession(), bufferedCommandControl);
417
fMICommandCache.setContextAvailable(fConnection.getContext(), true);
418
getSession().addServiceEventListener(this, null);
423
public void shutdown(final RequestMonitor rm) {
424
getSession().removeServiceEventListener(this);
425
fMICommandCache.reset();
429
public boolean isValid() { return true; }
432
protected boolean isResumePending() { return fResumePending; }
434
protected void setResumePending(boolean pending) { fResumePending = pending; }
436
protected boolean isTerminated() { return fTerminated; }
438
protected void setTerminated(boolean terminated) { fTerminated = terminated; }
440
public CommandCache getCache() { return fMICommandCache; }
442
protected ICommandControlService getConnection() { return fConnection; }
444
public IMIExecutionDMContext createMIExecutionContext(IContainerDMContext container, int threadId) {
445
return new MIExecutionDMC(getSession().getId(), container, threadId);
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.
452
@DsfServiceEventHandler
453
public void eventDispatched(final MIRunningEvent e) {
454
if (fDisableNextRunningEvent) {
455
fDisableNextRunningEvent = false;
456
// We don't broadcast this running event
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);
468
event = new ResumedEvent(e.getDMContext(), e);
470
getSession().dispatchEvent(event, getProperties());
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.
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
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);
494
final MIBreakpointDMContext bp = _bp;
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) {
510
protected void handleCompleted() {
511
IExecutionDMContext triggeringCtx2 = null;
512
if (isSuccess() && getData().getCurrentThread() != null) {
513
triggeringCtx2 = createMIExecutionContext(containerDmc, getData().getCurrentThread());
515
IDMEvent<?> event2 = bp != null
516
? new ContainerBreakpointHitEvent(containerDmc, (MIBreakpointHitEvent)e, triggeringCtx2, bp)
517
: new ContainerSuspendedEvent(containerDmc, e, triggeringCtx2);
518
getSession().dispatchEvent(event2, getProperties());
524
event = new ContainerBreakpointHitEvent(containerDmc, (MIBreakpointHitEvent)e, triggeringCtx, bp);
526
event = new ContainerSuspendedEvent(containerDmc, e, triggeringCtx);
530
event = new BreakpointHitEvent(e.getDMContext(), (MIBreakpointHitEvent)e, bp);
532
event = new SuspendedEvent(e.getDMContext(), e);
535
getSession().dispatchEvent(event, getProperties());
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.
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());
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.
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());
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.
568
@DsfServiceEventHandler
569
public void eventDispatched(ContainerResumedEvent e) {
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)) {
579
fMICommandCache.reset();
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.
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;
598
fResumePending = false;
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.
606
@DsfServiceEventHandler
607
public void eventDispatched(ICommandControlShutdownDMEvent e) {
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.
617
@DsfServiceEventHandler
618
public void eventDispatched(StartedDMEvent e) {
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.
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
633
fMICommandCache.setContextAvailable(e.getDMContext(), true);
634
fMICommandCache.reset();
638
fResumePending = false;
640
fMICommandCache.reset(e.getDMContext());
644
///////////////////////////////////////////////////////////////////////////
647
protected BundleContext getBundleContext() {
648
return GdbPlugin.getBundleContext();
651
///////////////////////////////////////////////////////////////////////////
653
public void canResume(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
654
rm.setData(doCanResume(context));
659
protected boolean doCanResume(IExecutionDMContext context) {
660
return !fTerminated && isSuspended(context) && !fResumePending;
663
public void canSuspend(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
664
rm.setData(doCanSuspend(context));
668
private boolean doCanSuspend(IExecutionDMContext context) {
669
return !fTerminated && !isSuspended(context);
672
public boolean isSuspended(IExecutionDMContext context) {
673
return !fTerminated && fSuspended;
676
public boolean isStepping(IExecutionDMContext context) {
677
return !fTerminated && fStepping;
680
public void resume(final IExecutionDMContext context, final RequestMonitor rm) {
681
assert context != null;
683
if (doCanResume(context)) {
684
ICommand<MIInfo> cmd = null;
685
if(context instanceof IContainerDMContext) {
686
cmd = fCommandFactory.createMIExecContinue(context);
688
IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
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$
694
cmd = fCommandFactory.createMIExecContinue(dmc);//, new String[0]);
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);
703
fConnection.queueCommand(
705
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
707
protected void handleFailure() {
708
fResumePending = false;
709
fMICommandCache.setContextAvailable(context, true);
711
super.handleFailure();
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$
721
public void suspend(IExecutionDMContext context, final RequestMonitor rm){
722
assert context != null;
724
if (doCanSuspend(context)) {
725
ICommand<MIInfo> cmd = null;
726
if(context instanceof IContainerDMContext){
727
cmd = fCommandFactory.createMIExecInterrupt(context);
730
IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
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$
736
cmd = fCommandFactory.createMIExecInterrupt(dmc);
738
fConnection.queueCommand(cmd, new DataRequestMonitor<MIInfo>(getExecutor(), rm));
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$
745
public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm) {
746
if (context instanceof IContainerDMContext) {
751
canResume(context, rm);
754
public void step(final IExecutionDMContext context, StepType stepType, final RequestMonitor rm) {
755
assert context != null;
757
IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
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$
764
if (!doCanResume(context)) {
765
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$
770
ICommand<MIInfo> cmd = null;
773
cmd = fCommandFactory.createMIExecStep(dmc, 1);
776
cmd = fCommandFactory.createMIExecNext(dmc);
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);
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$
795
case INSTRUCTION_STEP_INTO:
796
cmd = fCommandFactory.createMIExecStepInstruction(dmc, 1);
798
case INSTRUCTION_STEP_OVER:
799
cmd = fCommandFactory.createMIExecNextInstruction(dmc, 1);
802
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Given step type not supported", null)); //$NON-NLS-1$
807
fResumePending = true;
809
fMICommandCache.setContextAvailable(context, false);
811
fConnection.queueCommand(cmd, new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
813
public void handleFailure() {
814
fResumePending = false;
816
fMICommandCache.setContextAvailable(context, true);
818
super.handleFailure();
824
public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor<IExecutionDMContext[]> rm) {
825
fMICommandCache.execute(
826
fCommandFactory.createMIThreadListIds(containerDmc),
827
new DataRequestMonitor<MIThreadListIdsInfo>(
830
protected void handleSuccess() {
831
rm.setData(makeExecutionDMCs(containerDmc, getData()));
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)};
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]);
850
return executionDmcs;
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));
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$
869
protected void runToLocation(IExecutionDMContext context, String location, boolean skipBreakpoints, final RequestMonitor rm){
870
// skipBreakpoints is not used at the moment. Implement later
872
assert context != null;
874
IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
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$
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));
887
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
888
"Cannot resume given DMC.", null)); //$NON-NLS-1$
894
protected void resumeAtLocation(IExecutionDMContext context, String location, RequestMonitor rm) {
895
assert context != null;
897
final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
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$
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) {
911
protected void handleFailure() {
912
fResumePending = false;
913
fMICommandCache.setContextAvailable(dmc, true);
915
super.handleFailure();
919
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED,
920
"Cannot resume given DMC.", null)); //$NON-NLS-1$
925
/* ******************************************************************************
926
* Section to support operations even when the target is unavailable.
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
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
940
* See http://bugs.eclipse.org/337893
942
* ******************************************************************************/
945
* Utility class to store the parameters of the executeWithTargetAvailable() operations.
948
protected static class TargetAvailableOperationInfo {
949
public IDMContext ctx;
950
public Sequence.Step[] steps;
951
public RequestMonitor rm;
953
public TargetAvailableOperationInfo(IDMContext ctx, Step[] steps, RequestMonitor rm) {
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
970
private boolean fCurrentlyExecutingSteps;
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>();
988
* Returns whether the target is available to perform operations
991
protected boolean isTargetAvailable() {
992
return fTargetAvailable;
996
protected void setTargetAvailable(boolean available) {
997
fTargetAvailable = available;
1001
* Returns the execution context that needs to be suspended to perform the
1002
* required operation.
1005
protected IExecutionDMContext getContextToSuspend() {
1006
return fExecutionDmc;
1010
protected void setContextToSuspend(IExecutionDMContext context) {
1011
fExecutionDmc = context;
1015
* Returns whether there is currently an ExecuteWithTargetAvailable() operation ongoing.
1018
protected boolean isTargetAvailableOperationOngoing() {
1019
return fOngoingOperation;
1023
protected void setTargetAvailableOperationOngoing(boolean ongoing) {
1024
fOngoingOperation = ongoing;
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.
1033
protected boolean isCurrentlyExecutingSteps() {
1034
return fCurrentlyExecutingSteps;
1038
protected void setCurrentlyExecutingSteps(boolean executing) {
1039
fCurrentlyExecutingSteps = executing;
1043
* Returns the requestMonitor that will be run once all steps sent to
1044
* ExecuteWithTargetAvailable() have been executed.
1047
protected MultiRequestMonitor<RequestMonitor> getExecuteQueuedStepsRM() {
1048
return fExecuteQueuedOpsStepMonitor;
1052
protected void setExecuteQueuedStepsRM(MultiRequestMonitor<RequestMonitor> rm) {
1053
fExecuteQueuedOpsStepMonitor = rm;
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.
1063
protected int getNumStepsStillExecuting() {
1064
return fNumStepsStillExecuting;
1068
protected void setNumStepsStillExecuting(int num) {
1069
fNumStepsStillExecuting = num;
1073
* Returns the queue of executeWithTargetAvailable() operations that still need to be processed
1076
protected LinkedList<TargetAvailableOperationInfo> getOperationsPending() {
1077
return fOperationsPending;
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.
1087
protected void executeSteps(final TargetAvailableOperationInfo info) {
1088
fNumStepsStillExecuting++;
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) {
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.
1103
fExecuteQueuedOpsStepMonitor.requestMonitorDone(this);
1104
fNumStepsStillExecuting--;
1105
if (fNumStepsStillExecuting == 0) {
1106
fExecuteQueuedOpsStepMonitor.doneAdding();
1111
fExecuteQueuedOpsStepMonitor.add(stepsRm);
1113
getExecutor().execute(new Sequence(getExecutor(), stepsRm) {
1114
@Override public Step[] getSteps() { return info.steps; }
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;
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));
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(),
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) {
1142
protected void handleSuccess() {
1143
fOngoingOperation = false;
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);
1151
// no other rm.done() needs to be called, they have all been handled already
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;
1160
// Complete each rm of the cancelled operations
1161
while (fOperationsPending.size() > 0) {
1162
RequestMonitor rm = fOperationsPending.poll().rm;
1163
rm.setStatus(getStatus());
1167
super.handleFailure();
1171
getExecutor().execute(new Sequence(getExecutor(), sequenceCompletedRm) {
1172
@Override public Step[] getSteps() { return sequenceSteps; }
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));
1181
// Too late to execute the new steps, so queue them for later
1182
fOperationsPending.add(new TargetAvailableOperationInfo(ctx, steps, rm));
1189
* This part of the sequence verifies if the execution context of interest
1190
* is suspended or not.
1193
protected class IsTargetAvailableStep extends Sequence.Step {
1194
final IDMContext fCtx;
1196
public IsTargetAvailableStep(IDMContext ctx) {
1201
public void execute(final RequestMonitor rm) {
1202
fExecutionDmc = DMContexts.getAncestorOfType(fCtx, IMIContainerDMContext.class);
1203
if (fExecutionDmc != null) {
1204
fTargetAvailable = isSuspended(fExecutionDmc);
1209
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(fCtx, ICommandControlDMContext.class);
1210
IProcesses processControl = getServicesTracker().getService(IProcesses.class);
1211
processControl.getProcessesBeingDebugged(
1213
new DataRequestMonitor<IDMContext[]>(getExecutor(), rm) {
1215
protected void handleSuccess() {
1216
assert getData() != null;
1218
if (getData().length == 0) {
1219
// Happens at startup, starting with GDB 7.0.
1220
// This means the target is available
1221
fTargetAvailable = true;
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);
1235
* If the execution context of interest is not suspended, this step
1236
* will interrupt it.
1239
protected class MakeTargetAvailableStep extends Sequence.Step {
1241
public void execute(final RequestMonitor rm) {
1242
if (!isTargetAvailable()) {
1243
assert fDisableNextRunningEvent == false;
1244
assert fDisableNextSignalEvent == false;
1246
// Don't broadcast the coming stopped signal event
1247
fDisableNextSignalEvent = true;
1248
suspend(getContextToSuspend(),
1249
new RequestMonitor(getExecutor(), rm) {
1251
protected void handleFailure() {
1252
// We weren't able to suspend, so abort the operation
1253
fDisableNextSignalEvent = false;
1254
super.handleFailure();
1262
public void rollBack(RequestMonitor rm) {
1263
Sequence.Step restoreStep = new RestoreTargetStateStep();
1264
restoreStep.execute(rm);
1269
* This step of the sequence takes care of executing all the steps that
1270
* were passed to ExecuteWithTargetAvailable().
1273
protected class ExecuteQueuedOperationsStep extends Sequence.Step {
1275
public void execute(final RequestMonitor rm) {
1276
fCurrentlyExecutingSteps = true;
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) {
1282
protected void handleCompleted() {
1283
assert fOperationsPending.size() == 0;
1285
// We don't handle errors here. Instead, we have already propagated any
1286
// errors to each rm for each set of steps
1288
fCurrentlyExecutingSteps = false;
1289
// Continue the sequence
1293
// Tell the RM that we need to confirm when we are done adding sub-rms
1294
fExecuteQueuedOpsStepMonitor.requireDoneAdding();
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());
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.
1309
protected class RestoreTargetStateStep extends Sequence.Step {
1311
public void execute(final RequestMonitor rm) {
1312
if (!isTargetAvailable()) {
1313
assert fDisableNextRunningEvent == false;
1314
fDisableNextRunningEvent = true;
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) {
1322
protected void handleSuccess() {
1323
fSilencedSignalEvent = null;
1324
super.handleSuccess();
1328
protected void handleFailure() {
1329
// Darn, we're unable to restart the target. Must cleanup!
1330
fDisableNextRunningEvent = false;
1332
// We must also sent the Stopped event that we had kept silent
1333
if (fSilencedSignalEvent != null) {
1334
eventDispatched(fSilencedSignalEvent);
1335
fSilencedSignalEvent = null;
1337
// Maybe the stopped event didn't arrive yet.
1338
// We don't want to silence it anymore
1339
fDisableNextSignalEvent = false;
1342
super.handleFailure();
1346
// We didn't suspend the container, so we don't need to resume it
1352
/* ******************************************************************************
1353
* End of section to support operations even when the target is unavailable.
1354
* ******************************************************************************/
1360
public void flushCache(IDMContext context) {
1361
fMICommandCache.reset(context);
1364
private void moveToLocation(final IExecutionDMContext context,
1365
final String location, final Map<String, Object> bpAttributes,
1366
final RequestMonitor rm) {
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) {
1376
protected void handleSuccess() {
1377
// Now resume at the proper location
1378
resumeAtLocation(context, location, rm);
1382
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
1383
IDsfStatusConstants.NOT_SUPPORTED,
1384
"Unable to set breakpoint", null)); //$NON-NLS-1$
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)
1395
public void canRunToLine(IExecutionDMContext context, String sourceFile,
1396
int lineNumber, DataRequestMonitor<Boolean> rm) {
1397
canResume(context, rm);
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)
1406
public void runToLine(IExecutionDMContext context, String sourceFile,
1407
int lineNumber, boolean skipBreakpoints, RequestMonitor rm) {
1409
// Hack around a MinGW bug; see 196154
1410
sourceFile = MIBreakpointsManager.adjustDebuggerPath(sourceFile);
1412
runToLocation(context, sourceFile + ":" + Integer.toString(lineNumber), skipBreakpoints, rm); //$NON-NLS-1$
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)
1421
public void canRunToAddress(IExecutionDMContext context, IAddress address,
1422
DataRequestMonitor<Boolean> rm) {
1423
canResume(context, rm);
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)
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$
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)
1443
public void canMoveToLine(IExecutionDMContext context, String sourceFile,
1444
int lineNumber, boolean resume, DataRequestMonitor<Boolean> rm) {
1445
canResume(context, rm);
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)
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$
1463
String location = sourceFile + ":" + lineNumber; //$NON-NLS-1$
1465
resumeAtLocation(context, location, rm);
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()));
1475
// Now do the operation
1476
moveToLocation(context, location, attr, rm);
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)
1487
public void canMoveToAddress(IExecutionDMContext context, IAddress address,
1488
boolean resume, DataRequestMonitor<Boolean> rm) {
1489
canResume(context, rm);
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)
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$
1507
String location = "*0x" + address.toString(16); //$NON-NLS-1$
1509
resumeAtLocation(context, location, rm);
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()));
1518
// Now do the operation
1519
moveToLocation(context, location, attr, rm);
1525
public IRunMode getRunMode() {
1526
return MIRunMode.ALL_STOP;
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;