diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence_7_12.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence_7_12.java new file mode 100644 index 00000000000..8d85ec38eb8 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence_7_12.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2016 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.launching; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.debug.core.CDebugUtils; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitorWithProgress; +import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; +import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +/** + * Subclass for GDB >= 7.12. + * + * @since 5.2 + */ +public class FinalLaunchSequence_7_12 extends FinalLaunchSequence_7_7 { + private IGDBControl fCommandControl; + private CommandFactory fCommandFactory; + private Map fAttributes; + + public FinalLaunchSequence_7_12(DsfSession session, Map attributes, + RequestMonitorWithProgress rm) { + super(session, attributes, rm); + fAttributes = attributes; + } + + @Override + protected String[] getExecutionOrder(String group) { + if (GROUP_TOP_LEVEL.equals(group)) { + // Initialize the list with the base class' steps + // We need to create a list that we can modify, which is why we create our own ArrayList. + List orderList = new ArrayList( + Arrays.asList(super.getExecutionOrder(GROUP_TOP_LEVEL))); + + // Now insert our steps right after the initialization of the base class. + orderList.add(orderList.indexOf("stepInitializeFinalLaunchSequence_7_7") + 1, //$NON-NLS-1$ + "stepInitializeFinalLaunchSequence_7_12"); //$NON-NLS-1$ + + orderList.add(orderList.indexOf("stepSourceGDBInitFile") + 1, //$NON-NLS-1$ + "stepSetTargetAsync"); //$NON-NLS-1$ + + orderList.add(orderList.indexOf("stepSetTargetAsync") + 1, //$NON-NLS-1$ + "stepSetRecordFullStopAtLimit"); //$NON-NLS-1$ + + return orderList.toArray(new String[orderList.size()]); + } + + return null; + } + + /** + * Initialize the members of the FinalLaunchSequence_7_12 class. This step is mandatory for the rest of + * the sequence to complete. + */ + @Execute + public void stepInitializeFinalLaunchSequence_7_12(RequestMonitor rm) { + DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), + getSession().getId()); + fCommandControl = tracker.getService(IGDBControl.class); + tracker.dispose(); + + if (fCommandControl == null) { + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, + "Cannot obtain service", null)); //$NON-NLS-1$ + return; + } + + fCommandFactory = fCommandControl.getCommandFactory(); + + rm.done(); + + } + + @Execute + public void stepSetTargetAsync(RequestMonitor requestMonitor) { + // Use target async when interfacing with GDB 7.12 or higher + // this will allow us to use the new enhanced GDB Full CLI console + fCommandControl.queueCommand( + fCommandFactory.createMIGDBSetTargetAsync(fCommandControl.getContext(), true), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleError() { + // We should only be calling this for GDB >= 7.12, + // but just in case, accept errors for older GDBs + requestMonitor.done(); + } + }); + } + + /** + * Set reverse debugging record full stop-at-limit to off, so GDB does not halt waiting for user input + * when the recording buffer gets full + * @param requestMonitor + */ + @Execute + public void stepSetRecordFullStopAtLimit(RequestMonitor requestMonitor) { + fCommandControl.queueCommand( + fCommandFactory.createMIGDBSetRecordFullStopAtLimit(fCommandControl.getContext(), false), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleError() { + // Accept errors since this is not essential + requestMonitor.done(); + } + }); + } + + @Override + @Execute + public void stepSetNonStop(final RequestMonitor requestMonitor) { + boolean isNonStop = CDebugUtils.getAttribute(fAttributes, + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, + LaunchUtils.getIsNonStopModeDefault()); + + if (isNonStop) { + // GDBs that don't support non-stop don't allow you to set it to false. + // We really should set it to false when GDB supports it though. + // Something to fix later. + // Note that disabling pagination is taken care of elsewhere + fCommandControl.queueCommand( + fCommandFactory.createMIGDBSetNonStop(fCommandControl.getContext(), true), + new DataRequestMonitor(getExecutor(), requestMonitor)); + } else { + requestMonitor.done(); + } + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBackend_7_12.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBackend_7_12.java index 6e16c3451ab..a67c6698e2e 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBackend_7_12.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBackend_7_12.java @@ -14,7 +14,6 @@ import java.io.OutputStream; import org.eclipse.cdt.core.parser.util.StringUtil; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; -import org.eclipse.cdt.dsf.gdb.launching.LaunchUtils; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.utils.pty.PTY; import org.eclipse.cdt.utils.pty.PTY.Mode; @@ -48,20 +47,16 @@ public class GDBBackend_7_12 extends GDBBackend { /** Indicate that we failed to create a PTY. */ private boolean fPtyFailure; - private boolean fIsAllStop; - private InputStream fDummyErrorStream; public GDBBackend_7_12(DsfSession session, ILaunchConfiguration lc) { super(session, lc); - fIsAllStop = !LaunchUtils.getIsNonStopMode(lc); createPty(); } @Override public boolean isFullGdbConsoleSupported() { return !Platform.getOS().equals(Platform.OS_WIN32) - && !fIsAllStop && !fPtyFailure; } @@ -159,6 +154,12 @@ public class GDBBackend_7_12 extends GDBBackend { // Now trigger the new console towards our PTY. "-ex", "new-ui mi " + fMIPty.getSlaveName(), //$NON-NLS-1$ //$NON-NLS-2$ + // With GDB.7.12, pagination can lock up the whole debug session + // when using the full GDB console, so we turn it off. + // We must turn it off before calling 'show version' as even + // that command could cause pagination to trigger + "-ex", "set pagination off", //$NON-NLS-1$//$NON-NLS-2$ + // Now print the version so the user gets that familiar output "-ex", "show version" //$NON-NLS-1$ //$NON-NLS-2$ }; diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_12.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_12.java index 0e361157b7a..4f996dc8d4d 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_12.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_12.java @@ -7,11 +7,17 @@ *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Sequence; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext; @@ -29,6 +35,13 @@ public class GDBProcesses_7_12 extends GDBProcesses_7_10 { super(session); } + @Override + protected Sequence getStartOrRestartProcessSequence(DsfExecutor executor, + IContainerDMContext containerDmc, Map attributes, boolean restart, + DataRequestMonitor rm) { + return new StartOrRestartProcessSequence_7_12(executor, containerDmc, attributes, restart, rm); + } + @Override public void terminate(IThreadDMContext thread, RequestMonitor rm) { IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_10.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_10.java index e2664323f3b..d207f81cedb 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_10.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_10.java @@ -74,6 +74,17 @@ public class GDBRunControl_7_10 extends GDBRunControl_7_6 implements IReverseRun requestMonitor.done(); } + @Override + public void setReverseModeEnabled(boolean enabled) { + super.setReverseModeEnabled(enabled); + if (!enabled) { + // Keep the disabled state in sync with the trace method + // This is needed e.g. to restart reverse mode during + // a process restart + fReverseTraceMethod = ReverseDebugMethod.OFF; + } + } + /** @since 5.1 */ protected void setReverseTraceMethod(ReverseDebugMethod traceMethod) { if (fReverseTraceMethod != traceMethod) { diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_12.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_12.java new file mode 100644 index 00000000000..dd1ebb7e585 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_12.java @@ -0,0 +1,356 @@ +/******************************************************************************* + * Copyright (c) 2016 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.service; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.cdt.debug.core.model.IChangeReverseMethodHandler.ReverseDebugMethod; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.mi.service.IMICommandControl; +import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; +import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; +import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent; +import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent; +import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; +import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; + +/** + * @since 5.2 + */ +public class GDBRunControl_7_12 extends GDBRunControl_7_10 { + private IMICommandControl fCommandControl; + private CommandFactory fCommandFactory; + private Map fBpIdToReverseOpMap = new HashMap<>(); + + public GDBRunControl_7_12(DsfSession session) { + super(session); + } + + @Override + public void initialize(final RequestMonitor rm) { + super.initialize(new ImmediateRequestMonitor(rm) { + @Override + protected void handleSuccess() { + doInitialize(rm); + } + }); + } + + private void doInitialize(final RequestMonitor rm) { + fCommandControl = getServicesTracker().getService(IMICommandControl.class); + fCommandFactory = fCommandControl.getCommandFactory(); + + register(new String[]{ GDBRunControl_7_12.class.getName() }, + new Hashtable()); + + rm.done(); + } + + @Override + public void suspend(IExecutionDMContext context, final RequestMonitor rm){ + canSuspend( + context, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (getData()) { + // Thread or Process + doSuspend(context, rm); + } else { + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Context cannot be suspended.", null)); //$NON-NLS-1$ + } + } + }); + } + + private void doSuspend(IExecutionDMContext context, final RequestMonitor rm) { + // Start the job before sending the interrupt command + // to make sure we don't miss the *stopped event + final MonitorSuspendJob monitorJob = new MonitorSuspendJob(0, rm); + fCommandControl.queueCommand(fCommandFactory.createMIExecInterrupt(context), + new ImmediateDataRequestMonitor() { + @Override + protected void handleSuccess() { + // Nothing to do in the case of success, the monitoring job + // will take care of completing the RM once it gets the + // *stopped event. + } + + @Override + protected void handleFailure() { + // In case of failure, we must cancel the monitoring job + // and indicate the failure in the rm. + monitorJob.cleanAndCancel(); + rm.done(getStatus()); + } + }); + } + + @Override + public boolean isTargetAcceptingCommands() { + // Async mode is on when running with GDB 7.12 or higher + return true; + } + + /** + * @since 5.2 + */ + @DsfServiceEventHandler + public void eventDispatched(ISuspendedDMEvent event) { + assert event instanceof IMIDMEvent; + + if (event instanceof IMIDMEvent) { + Object evt = ((IMIDMEvent)event).getMIEvent(); + + if (evt instanceof MIBreakpointHitEvent) { + MIBreakpointHitEvent miEvt = (MIBreakpointHitEvent)evt; + + for (EnableReverseAtLocOperation enableReverse : fBpIdToReverseOpMap.values()) { + if (breakpointHitMatchesLocation(miEvt, enableReverse)) { + // We are now stopped at the right place to initiate the recording for reverse mode + // Remove the operation from our internal map and process it + fBpIdToReverseOpMap.remove(enableReverse.fBpId); + IContainerDMContext containerContext = enableReverse.getContainerContext(); + ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(containerContext, ICommandControlDMContext.class); + ReverseDebugMethod reverseMethod = enableReverse.getReverseDebugMethod(); + if (controlDmc != null && reverseMethod != null) { + enableReverseMode(controlDmc, reverseMethod, new RequestMonitor(getExecutor(), null) { + @Override + protected void handleSuccess() { + if (enableReverse.shouldTriggerContinue()) { + fCommandControl.queueCommand(fCommandFactory.createMIExecContinue(containerContext), + new ImmediateDataRequestMonitor()); + } + } + }); + } + + // Not expecting more than one operation for the same location + break; + } + } + } + } + } + + private static class EnableReverseAtLocOperation { + private final IContainerDMContext fContainerContext; + private final ReverseDebugMethod fTraceMethod; + private final String fBpId; + private final String fFileLocation; + private final String fAddrLocation; + private final boolean fTriggerContinue; + + public EnableReverseAtLocOperation(IContainerDMContext containerContext, ReverseDebugMethod traceMethod, + String bpId, String fileLoc, String addr, boolean tiggerContinue) { + fContainerContext = containerContext; + fTraceMethod = traceMethod; + fBpId = bpId; + fFileLocation = fileLoc; + fAddrLocation = addr; + fTriggerContinue = tiggerContinue; + } + + public IContainerDMContext getContainerContext() { + return fContainerContext; + } + + public ReverseDebugMethod getReverseDebugMethod() { + return fTraceMethod; + } + + public String getBreakointId() { + return fBpId; + } + + public String getFileLocation() { + return fFileLocation; + } + + public String getAddrLocation() { + return fAddrLocation; + } + + public boolean shouldTriggerContinue() { + return fTriggerContinue; + } + + @Override + public int hashCode() { + return fBpId.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof EnableReverseAtLocOperation) { + if (fContainerContext != null + && fContainerContext.equals(((EnableReverseAtLocOperation) other).fContainerContext) + && fTraceMethod != null + && fTraceMethod.equals(((EnableReverseAtLocOperation) other).fTraceMethod) + && fBpId != null + && fBpId.equals(((EnableReverseAtLocOperation) other).fBpId) + && fFileLocation != null + && fFileLocation.equals(((EnableReverseAtLocOperation) other).fFileLocation) + && fAddrLocation != null + && fAddrLocation.equals(((EnableReverseAtLocOperation) other).fAddrLocation) + && fTriggerContinue == ((EnableReverseAtLocOperation) other).fTriggerContinue) { + return true; + } + } + return false; + } + } + + /** + * Changes the reverse debugging method as soon as the program is suspended at the specified breakpoint location + * + * It is recommended to use this request before the program runs or restarts in order to prevent timing issues and + * miss a suspend event + * + * Note, using the break point id to determine the stop location would be sufficient although in the case where + * multiple break points are inserted in the same location, GDB will only report one of them (e.g. GDB 7.12) + * + * Having the MIBreakpoint will give us access to the address, file and line number as well which can be used as + * alternatives to determine a matched location. + * + * This method is specially useful when using async mode with i.e. with GDB 7.12. + * Activating reverse debugging when the target is running may trigger an unresponsive GDB, this triggered the + * creation of this method + * + */ + void enableReverseModeAtBpLocation(final IContainerDMContext containerContext, final ReverseDebugMethod traceMethod, + MIBreakpoint bp, boolean triggerContinue) { + + // Using an internal convention for file location i.e. file:lineNumber + String fileLoc = bp.getFile() + ":" + bp.getLine(); //$NON-NLS-1$ + + fBpIdToReverseOpMap.put(bp.getNumber(), new EnableReverseAtLocOperation(containerContext, traceMethod, + bp.getNumber(), fileLoc, bp.getAddress(), triggerContinue)); + } + + private boolean breakpointHitMatchesLocation(MIBreakpointHitEvent e, EnableReverseAtLocOperation enableReverse) { + if (enableReverse != null) { + String bpId = e.getNumber(); + + // Here we check three different things to see if we are stopped at the right place + // 1- The actual location in the file. But this does not work for breakpoints that + // were set on non-executable lines + // 2- The address where the breakpoint was set. But this does not work for breakpoints + // that have multiple addresses (GDB returns .) I think that is for multi-process + // 3- The breakpoint id that was hit. But this does not work if another breakpoint + // was also set on the same line because GDB may return that breakpoint as being hit. + // + // So this works for the large majority of cases. The case that won't work is when the user + // does a runToLine to a line that is non-executable AND has another breakpoint AND + // has multiple addresses for the breakpoint. I'm mean, come on! + boolean equalFileLocation = false; + boolean equalAddrLocation = false; + boolean equalBpId = bpId.equals(enableReverse.getBreakointId()); + MIFrame frame = e.getFrame(); + if(frame != null) { + String fileLocation = frame.getFile() + ":" + frame.getLine(); //$NON-NLS-1$ + String addrLocation = frame.getAddress(); + equalFileLocation = fileLocation.equals(enableReverse.getFileLocation()); + equalAddrLocation = addrLocation.equals(enableReverse.getAddrLocation()); + } + + if (equalFileLocation || equalAddrLocation || equalBpId) { + // We stopped at the right place + return true; + } + } + + return false; + } + + protected class MonitorSuspendJob extends Job { + // Bug 310274. Until we have a preference to configure timeouts, + // we need a large enough default timeout to accommodate slow + // remote sessions. + private final static int TIMEOUT_DEFAULT_VALUE = 5000; + + private final RequestMonitor fRequestMonitor; + + public MonitorSuspendJob(int timeout, RequestMonitor rm) { + super("Suspend monitor job."); //$NON-NLS-1$ + setSystem(true); + fRequestMonitor = rm; + + if (timeout <= 0) { + timeout = TIMEOUT_DEFAULT_VALUE; // default of 5 seconds + } + + // Register to listen for the stopped event + getSession().addServiceEventListener(this, null); + + schedule(timeout); + } + + /** + * Cleanup job and cancel it. + * This method is required because super.canceling() is only called + * if the job is actually running. + */ + public boolean cleanAndCancel() { + if (getExecutor().isInExecutorThread()) { + getSession().removeServiceEventListener(this); + } else { + getExecutor().submit( + new DsfRunnable() { + @Override + public void run() { + getSession().removeServiceEventListener(MonitorSuspendJob.this); + } + }); + } + return cancel(); + } + + @DsfServiceEventHandler + public void eventDispatched(MIStoppedEvent e) { + if (e.getDMContext() != null && e.getDMContext() instanceof IMIExecutionDMContext ) { + // For all-stop, this means all threads have stopped + if (cleanAndCancel()) { + fRequestMonitor.done(); + } + } + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + // This will be called when the timeout is hit and no *stopped event was received + getExecutor().submit( + new DsfRunnable() { + @Override + public void run() { + getSession().removeServiceEventListener(MonitorSuspendJob.this); + fRequestMonitor.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Suspend operation timeout.", null)); //$NON-NLS-1$ + } + }); + return Status.OK_STATUS; + } + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java index 77e40705ba7..90360caf175 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java @@ -45,6 +45,7 @@ import org.eclipse.cdt.dsf.gdb.launching.LaunchUtils; import org.eclipse.cdt.dsf.gdb.service.command.CommandFactory_6_8; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_0; +import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_12; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_2; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_4; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_7; @@ -212,6 +213,9 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { } protected ICommandControl createCommandControl(DsfSession session, ILaunchConfiguration config) { + if (compareVersionWith(GDB_7_12_VERSION) >= 0) { + return new GDBControl_7_12(session, config, new CommandFactory_6_8()); + } if (compareVersionWith(GDB_7_7_VERSION) >= 0) { return new GDBControl_7_7(session, config, new CommandFactory_6_8()); } @@ -318,6 +322,9 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { } // Else, handle all-stop mode + if (compareVersionWith(GDB_7_12_VERSION) >= 0) { + return new GDBRunControl_7_12(session); + } if (compareVersionWith(GDB_7_10_VERSION) >= 0) { return new GDBRunControl_7_10(session); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java index 9886bf8d86e..f0e23cfc398 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java @@ -80,6 +80,7 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence { // on the main() method. private boolean fUserBreakpointIsOnMain; + private MIBreakpoint fBreakPointForReverse; private boolean fReverseEnabled; private final Map fAttributes; @@ -100,11 +101,18 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence { protected MIBreakpoint getUserBreakpoint() { return fUserBreakpoint; } - + + /** + * @since 5.2 + */ + protected MIBreakpoint getBreakPointForReverse() { + return fBreakPointForReverse; + } + protected boolean getUserBreakpointIsOnMain() { return fUserBreakpointIsOnMain; } - + /** @since 5.0 */ protected boolean getReverseEnabled() { return fReverseEnabled; @@ -243,8 +251,11 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence { public void handleSuccess() { if (getData() != null) { MIBreakpoint[] breakpoints = getData().getMIBreakpoints(); - if (breakpoints.length > 0 && fUserBreakpoint != null) { - fUserBreakpointIsOnMain = breakpoints[0].getAddress().equals(fUserBreakpoint.getAddress()); + if (breakpoints.length > 0) { + fBreakPointForReverse = breakpoints[0]; + if (fUserBreakpoint != null) { + fUserBreakpointIsOnMain = fBreakPointForReverse.getAddress().equals(fUserBreakpoint.getAddress()); + } } } rm.done(); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_10.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_10.java index e094169c1f4..bfd19929dbe 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_10.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_10.java @@ -111,7 +111,13 @@ public class StartOrRestartProcessSequence_7_10 extends StartOrRestartProcessSeq } }); } - + + /** + * @since 5.2 + */ + protected ReverseDebugMethod getReverseMode() { + return fReverseMode; + } /** * Here we set the reverse debug mode diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_12.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_12.java new file mode 100644 index 00000000000..57b712e7e42 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_12.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2016 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; + +/** + * @since 5.2 + */ +public class StartOrRestartProcessSequence_7_12 extends StartOrRestartProcessSequence_7_10 { + private GDBRunControl_7_12 fReverseService; + + public StartOrRestartProcessSequence_7_12(DsfExecutor executor, IContainerDMContext containerDmc, + Map attributes, boolean restart, DataRequestMonitor rm) { + super(executor, containerDmc, attributes, restart, rm); + } + + /** + * Initialize the members of the StartOrRestartProcessSequence_7_12 class. + * This step is mandatory for the rest of the sequence to complete. + */ + @Override + @Execute + public void stepInitializeBaseSequence(final RequestMonitor rm) { + super.stepInitializeBaseSequence(new ImmediateRequestMonitor(rm) { + @Override + protected void handleSuccess() { + DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), + getContainerContext().getSessionId()); + fReverseService = tracker.getService(GDBRunControl_7_12.class); + tracker.dispose(); + rm.done(); + }; + }); + } + + @Override + protected String[] getExecutionOrder(String group) { + if (GROUP_TOP_LEVEL.equals(group)) { + // Initialize the list with the base class' steps + // We need to create a list that we can modify, which is why we create our own ArrayList. + List orderList = new ArrayList(Arrays.asList(super.getExecutionOrder(GROUP_TOP_LEVEL))); + + // Need to insert reverse mode off before ordering the reverse start at a specified location + orderList.add(orderList.indexOf("stepCreateConsole") + 1, "stepSetReverseOff2"); //$NON-NLS-1$ //$NON-NLS-2$ + + // Order the activation of reverse debugging before starting the program, it will be executed once the + // program stops at the specified location. + orderList.add(orderList.indexOf("stepSetReverseOff2") + 1, "stepSetReverseModeAtLocation"); //$NON-NLS-1$ //$NON-NLS-2$ + + return orderList.toArray(new String[orderList.size()]); + } + + return null; + } + + @Execute + public void stepSetReverseOff2(RequestMonitor rm) { + super.stepSetReverseOff(rm); + } + + /** + * Request the enabling of reverse debugging, it will be applied once the program + * stops at the breakpoint inserted for reverse debugging + */ + @Execute + public void stepSetReverseModeAtLocation(final RequestMonitor rm) { + MIBreakpoint bp = getBreakPointForReverse(); + if (getReverseEnabled() && fReverseService != null && bp != null) { + // Order to continue execution if there is no user break point inserted at main + fReverseService.enableReverseModeAtBpLocation(getContainerContext(), getReverseMode(), bp, + !getUserBreakpointIsOnMain()); + } + rm.done(); + } + + /* + * We have scheduled the start of reverse debug, so we shall skip this method from super class + */ + @Override + @Execute + public void stepSetReverseMode(RequestMonitor rm) { + rm.done(); + } + + /* + * We have scheduled the start of reverse debug, so we shall skip this method from super class + */ + @Override + @Execute + public void stepEnableReverse(RequestMonitor rm) { + rm.done(); + } + + /* + * The order to continue or not has been included with the order to start reverse debugging at a specific location + * so we shall skip this method from super class + */ + @Override + @Execute + public void stepContinue(RequestMonitor rm) { + rm.done(); + } + +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_12.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_12.java new file mode 100644 index 00000000000..5c8712cf175 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_12.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2016 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.service.command; + +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.RequestMonitorWithProgress; +import org.eclipse.cdt.dsf.concurrent.Sequence; +import org.eclipse.cdt.dsf.gdb.launching.FinalLaunchSequence_7_12; +import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.debug.core.ILaunchConfiguration; + +/** + * Need a new FinalLaunchSequence for GDB 7.12 + * @since 5.2 + */ +public class GDBControl_7_12 extends GDBControl_7_7 { + public GDBControl_7_12(DsfSession session, ILaunchConfiguration config, CommandFactory factory) { + super(session, config, factory); + } + + @Override + protected Sequence getCompleteInitializationSequence(Map attributes, RequestMonitorWithProgress rm) { + return new FinalLaunchSequence_7_12(getSession(), attributes, rm); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/extensions/GDBControl_HEAD.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/extensions/GDBControl_HEAD.java index e4015e55882..0c2a9b59d2d 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/extensions/GDBControl_HEAD.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/extensions/GDBControl_HEAD.java @@ -9,7 +9,7 @@ package org.eclipse.cdt.dsf.gdb.service.extensions; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.gdb.service.GdbDebugServicesFactory; -import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_7; +import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_12; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.debug.core.ILaunchConfiguration; @@ -38,14 +38,14 @@ import org.eclipse.debug.core.ILaunchConfiguration; * * @since 4.8 */ -public class GDBControl_HEAD extends GDBControl_7_7 { +public class GDBControl_HEAD extends GDBControl_7_12 { public GDBControl_HEAD(DsfSession session, ILaunchConfiguration lc, CommandFactory factory) { super(session, lc, factory); validateGdbVersion(session); } - protected String getMinGDBVersionSupported() { return GdbDebugServicesFactory.GDB_7_7_VERSION; } + protected String getMinGDBVersionSupported() { return GdbDebugServicesFactory.GDB_7_12_VERSION; } protected void validateGdbVersion(DsfSession session) { GdbDebugServicesFactory.validateGdbVersion(session, getMinGDBVersionSupported(), this); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/extensions/GDBRunControl_HEAD.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/extensions/GDBRunControl_HEAD.java index 40f12c33a83..b152e475656 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/extensions/GDBRunControl_HEAD.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/extensions/GDBRunControl_HEAD.java @@ -8,7 +8,7 @@ package org.eclipse.cdt.dsf.gdb.service.extensions; import org.eclipse.cdt.dsf.debug.service.IRunControl; -import org.eclipse.cdt.dsf.gdb.service.GDBRunControl_7_10; +import org.eclipse.cdt.dsf.gdb.service.GDBRunControl_7_12; import org.eclipse.cdt.dsf.gdb.service.GdbDebugServicesFactory; import org.eclipse.cdt.dsf.service.DsfSession; @@ -37,14 +37,14 @@ import org.eclipse.cdt.dsf.service.DsfSession; * * @since 4.8 */ -public class GDBRunControl_HEAD extends GDBRunControl_7_10 { +public class GDBRunControl_HEAD extends GDBRunControl_7_12 { public GDBRunControl_HEAD(DsfSession session) { super(session); validateGdbVersion(session); } - protected String getMinGDBVersionSupported() { return GdbDebugServicesFactory.GDB_7_10_VERSION; } + protected String getMinGDBVersionSupported() { return GdbDebugServicesFactory.GDB_7_12_VERSION; } protected void validateGdbVersion(DsfSession session) { GdbDebugServicesFactory.validateGdbVersion(session, getMinGDBVersionSupported(), this); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java index 5e89614a0f9..1dedb89d0e1 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java @@ -135,6 +135,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetPagination; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetPrintObject; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetPrintSevenbitStrings; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetPythonPrintStack; +import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetRecordFullStopAtLimit; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetSchedulerLocking; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetSolibAbsolutePrefix; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetSolibSearchPath; @@ -821,6 +822,11 @@ public class CommandFactory { return new MIGDBSetPythonPrintStack(ctx, option); } + /** @since 5.2 */ + public ICommand createMIGDBSetRecordFullStopAtLimit(ICommandControlDMContext ctx, boolean isSet) { + return new MIGDBSetRecordFullStopAtLimit(ctx, isSet); + } + /** @since 4.1 */ public ICommand createMIGDBSetSchedulerLocking(ICommandControlDMContext ctx, String mode) { return new MIGDBSetSchedulerLocking(ctx, mode); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIGDBSetRecordFullStopAtLimit.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIGDBSetRecordFullStopAtLimit.java new file mode 100644 index 00000000000..3764472c44b --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIGDBSetRecordFullStopAtLimit.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2016 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service.command.commands; + +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; + +/** + * -gdb-set record full stop-at-limit [on | off] + * @since 5.2 + * + */ +public class MIGDBSetRecordFullStopAtLimit extends MIGDBSet +{ + public MIGDBSetRecordFullStopAtLimit(ICommandControlDMContext ctx, boolean isSet) { + super(ctx, new String[] {"record", "full", "stop-at-limit", isSet ? "on" : "off"});//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + } +} \ No newline at end of file diff --git a/dsf-gdb/org.eclipse.cdt.examples.dsf.gdb/src/org/eclipse/cdt/examples/dsf/gdb/launch/GdbExtendedFinalLaunchSequence.java b/dsf-gdb/org.eclipse.cdt.examples.dsf.gdb/src/org/eclipse/cdt/examples/dsf/gdb/launch/GdbExtendedFinalLaunchSequence.java index 6093cfe169e..1e6e6ddce23 100644 --- a/dsf-gdb/org.eclipse.cdt.examples.dsf.gdb/src/org/eclipse/cdt/examples/dsf/gdb/launch/GdbExtendedFinalLaunchSequence.java +++ b/dsf-gdb/org.eclipse.cdt.examples.dsf.gdb/src/org/eclipse/cdt/examples/dsf/gdb/launch/GdbExtendedFinalLaunchSequence.java @@ -19,7 +19,7 @@ import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitorWithProgress; -import org.eclipse.cdt.dsf.gdb.launching.FinalLaunchSequence_7_7; +import org.eclipse.cdt.dsf.gdb.launching.FinalLaunchSequence_7_12; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.service.DsfServicesTracker; @@ -29,7 +29,7 @@ import org.eclipse.cdt.examples.dsf.gdb.service.IGDBExtendedFunctions; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -public class GdbExtendedFinalLaunchSequence extends FinalLaunchSequence_7_7 { +public class GdbExtendedFinalLaunchSequence extends FinalLaunchSequence_7_12 { private IGDBControl fControl; private DsfServicesTracker fTracker;