diff options
Diffstat (limited to 'dsf-gdb')
19 files changed, 1684 insertions, 104 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java index 51d5f2ea88b..fb440c46362 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems and others. + * Copyright (c) 2006, 2013 Wind River Systems 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 @@ -9,6 +9,7 @@ * Wind River Systems - initial API and implementation * Navid Mehregani (TI) - Bug 289526 - Migrate the Restart feature to the new one, as supported by the platform * Patrick Chuong (Texas Instruments) - Add support for icon overlay in the debug view (Bug 334566) + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal.ui; @@ -27,6 +28,7 @@ import org.eclipse.cdt.debug.core.model.IReverseStepOverHandler; import org.eclipse.cdt.debug.core.model.IReverseToggleHandler; import org.eclipse.cdt.debug.core.model.ISaveTraceDataHandler; import org.eclipse.cdt.debug.core.model.IStartTracingHandler; +import org.eclipse.cdt.debug.core.model.IStepIntoSelectionHandler; import org.eclipse.cdt.debug.core.model.ISteppingModeTarget; import org.eclipse.cdt.debug.core.model.IStopTracingHandler; import org.eclipse.cdt.debug.core.model.IUncallHandler; @@ -35,9 +37,11 @@ import org.eclipse.cdt.dsf.concurrent.Immutable; import org.eclipse.cdt.dsf.concurrent.ThreadSafe; import org.eclipse.cdt.dsf.debug.ui.actions.DsfResumeCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepIntoCommand; +import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepIntoSelectionCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepOverCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepReturnCommand; import org.eclipse.cdt.dsf.debug.ui.actions.DsfSuspendCommand; +import org.eclipse.cdt.dsf.debug.ui.actions.IDsfStepIntoSelection; import org.eclipse.cdt.dsf.debug.ui.sourcelookup.DsfSourceDisplayAdapter; import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController; import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.DefaultRefreshAllTarget; @@ -105,6 +109,7 @@ public class GdbAdapterFactory final GdbViewModelAdapter fViewModelAdapter; final DsfSourceDisplayAdapter fSourceDisplayAdapter; final DsfStepIntoCommand fStepIntoCommand; + final DsfStepIntoSelectionCommand fStepIntoSelectionCommand; final GdbReverseStepIntoCommand fReverseStepIntoCommand; final DsfStepOverCommand fStepOverCommand; final GdbReverseStepOverCommand fReverseStepOverCommand; @@ -154,6 +159,7 @@ public class GdbAdapterFactory fSteppingModeTarget = new GdbSteppingModeTarget(session); fStepIntoCommand = new DsfStepIntoCommand(session, fSteppingModeTarget); + fStepIntoSelectionCommand = new DsfStepIntoSelectionCommand(session); fReverseStepIntoCommand = new GdbReverseStepIntoCommand(session, fSteppingModeTarget); fStepOverCommand = new DsfStepOverCommand(session, fSteppingModeTarget); fReverseStepOverCommand = new GdbReverseStepOverCommand(session, fSteppingModeTarget); @@ -181,6 +187,7 @@ public class GdbAdapterFactory session.registerModelAdapter(ISteppingModeTarget.class, fSteppingModeTarget); session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand); + session.registerModelAdapter(IStepIntoSelectionHandler.class, fStepIntoSelectionCommand); session.registerModelAdapter(IReverseStepIntoHandler.class, fReverseStepIntoCommand); session.registerModelAdapter(IStepOverHandler.class, fStepOverCommand); session.registerModelAdapter(IReverseStepOverHandler.class, fReverseStepOverCommand); @@ -204,6 +211,7 @@ public class GdbAdapterFactory session.registerModelAdapter(ISelectNextTraceRecordHandler.class, fSelectNextRecordTarget); session.registerModelAdapter(ISelectPrevTraceRecordHandler.class, fSelectPrevRecordTarget); session.registerModelAdapter(IPinProvider.class, fPinProvider); + session.registerModelAdapter(IDsfStepIntoSelection.class, fStepIntoSelectionCommand); fDebugModelProvider = new IDebugModelProvider() { // @see org.eclipse.debug.core.model.IDebugModelProvider#getModelIdentifiers() @@ -242,6 +250,7 @@ public class GdbAdapterFactory session.unregisterModelAdapter(ISteppingModeTarget.class); session.unregisterModelAdapter(IStepIntoHandler.class); + session.unregisterModelAdapter(IStepIntoSelectionHandler.class); session.unregisterModelAdapter(IReverseStepIntoHandler.class); session.unregisterModelAdapter(IStepOverHandler.class); session.unregisterModelAdapter(IReverseStepOverHandler.class); @@ -273,6 +282,7 @@ public class GdbAdapterFactory fSteppingModeTarget.dispose(); fStepIntoCommand.dispose(); + fStepIntoSelectionCommand.dispose(); fReverseStepIntoCommand.dispose(); fStepOverCommand.dispose(); fReverseStepOverCommand.dispose(); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF b/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF index 875fd3ece60..59bbcce538b 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF @@ -23,6 +23,7 @@ Export-Package: org.eclipse.cdt.dsf.gdb, org.eclipse.cdt.dsf.gdb.internal;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.debug.gdbjtag.ui", org.eclipse.cdt.dsf.gdb.internal.commands;x-friends:="org.eclipse.cdt.dsf.gdb.ui", org.eclipse.cdt.dsf.gdb.internal.memory;x-internal:=true, + org.eclipse.cdt.dsf.gdb.internal.service.control;x-internal:=true, org.eclipse.cdt.dsf.gdb.internal.service.command.events;x-internal:=true, org.eclipse.cdt.dsf.gdb.internal.tracepointactions;x-friends:="org.eclipse.cdt.dsf.gdb.ui", org.eclipse.cdt.dsf.gdb.launching, diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java index ee19d3c3678..60fd44bb351 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011 Mentor Graphics and others. + * Copyright (c) 2011, 2013 Mentor Graphics and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * Mentor Graphics - Initial API and implementation + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal; @@ -22,6 +23,11 @@ public class Messages extends NLS { public static String CustomTimeoutsMap_Invalid_custom_timeout_value; public static String GDBControl_Session_is_terminated; + + public static String StepIntoSelection; + + public static String StepIntoSelection_Execution_did_not_enter_function; + static { // initialize resource bundle NLS.initializeMessages( Messages.class.getName(), Messages.class ); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties index 9a4e8c3dbbe..978adaa94e6 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties @@ -1,5 +1,5 @@ ####################################################################################### -# Copyright (c) 2011 Mentor Graphics and others. +# Copyright (c) 2011, 2013 Mentor Graphics and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at @@ -7,9 +7,12 @@ # # Contributors: # Mentor Graphics - Initial API and implementation +# Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection ####################################################################################### CustomTimeoutsMap_Error_initializing_custom_timeouts=Error initializing custom timeouts CustomTimeoutsMap_Invalid_custom_timeout_data=Invalid custom timeout data. CustomTimeoutsMap_Invalid_custom_timeout_value=Invalid custom timeout value for '%s'. GDBControl_Session_is_terminated=Session is terminated.\nReason: %s +StepIntoSelection=Step into selection +StepIntoSelection_Execution_did_not_enter_function=Execution did not enter \"{0}\" diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionActiveOperation.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionActiveOperation.java new file mode 100644 index 00000000000..8f9e5c29e11 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionActiveOperation.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2013 Ericsson AB and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.service.control; + +import org.eclipse.cdt.core.model.IFunctionDeclaration; +import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; +import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame; + +/** + * @since 4.2 + */ +public class StepIntoSelectionActiveOperation { + private final IFunctionDeclaration fTargetFunction; + private final IMIExecutionDMContext fThreadContext; + private String fBaseFileLocation = null; + private int fBaseLine = 0; + private int fOriginalStackDepth=0; + private String fFunctionSignature = null; + private MIFrame fRunToLineFrame = null; + + public StepIntoSelectionActiveOperation(IMIExecutionDMContext threadContext, int line, IFunctionDeclaration targetFunction, + int stackDepth, MIFrame runToLineFrame) { + fThreadContext = threadContext; + fBaseLine = line; + fTargetFunction = targetFunction; + fOriginalStackDepth = stackDepth; + + fRunToLineFrame = runToLineFrame; + init(); + } + + private void init() { + if (fRunToLineFrame == null) { + return; + } + + fBaseFileLocation = fRunToLineFrame.getFile() + ":" + fBaseLine; //$NON-NLS-1$ + } + + public IFunctionDeclaration getTargetFunctionDeclaration() { + return fTargetFunction; + } + + public IMIExecutionDMContext getThreadContext() { + return fThreadContext; + } + + public String getFileLocation() { + return fBaseFileLocation; + } + + public int getLine() { + return fBaseLine; + } + + public int getOriginalStackDepth() { + return fOriginalStackDepth; + } + + public void setOriginalStackDepth(Integer originalStackDepth) { + fOriginalStackDepth = originalStackDepth; + } + + public MIFrame getRunToLineFrame() { + return fRunToLineFrame; + } + + public void setRunToLineFrame(MIFrame runToLineFrame) { + if (runToLineFrame != null) { + fRunToLineFrame = runToLineFrame; + init(); + } + } + + public String getTargetFunctionSignature() { + if (fFunctionSignature != null) { + return fFunctionSignature; + } else { + if (fTargetFunction != null) { + StringBuilder sb = null; + sb = new StringBuilder(); + if (fTargetFunction.getParent() != null) { + sb.append(fTargetFunction.getParent().getElementName() + StepIntoSelectionUtils.cppSep); + } + + sb.append(fTargetFunction.getElementName()); + fFunctionSignature = sb.toString(); + } + } + + return fFunctionSignature; + } +}
\ No newline at end of file diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionUtils.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionUtils.java new file mode 100644 index 00000000000..590404dde97 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionUtils.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2013 Ericsson AB and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.service.control; + +import org.eclipse.cdt.dsf.gdb.IGdbDebugConstants; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.internal.Messages; +import org.eclipse.cdt.dsf.mi.service.command.output.MIArg; +import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.osgi.util.NLS; + +public class StepIntoSelectionUtils { + + public static final String cppSep = "::"; //$NON-NLS-1$ + + public static boolean sameSignature(MIFrame currentFrame, StepIntoSelectionActiveOperation stepOperation) { + String currentFunctionName = currentFrame.getFunction(); + String targetFunctionName = stepOperation.getTargetFunctionSignature(); + + if (!sameNumberOfArgumets(currentFrame, stepOperation)) { + return false; + } + + // Simplified validation + if (currentFunctionName.equals(targetFunctionName)) { + return true; + } + + // Check if the last segment of the function name match + String[] currentFunctTokens = currentFunctionName.split(cppSep); + String[] targetFunctTokens = targetFunctionName.split(cppSep); + if (currentFunctTokens.length > 1) { + currentFunctionName = currentFunctTokens[currentFunctTokens.length - 1]; + } + + if (targetFunctTokens.length > 1) { + targetFunctionName = targetFunctTokens[targetFunctTokens.length - 1]; + } + + if (currentFunctionName.equals(targetFunctionName)) { + // Function name matches and parent name does not. One of the parents may be a super class + // Simple enough for initial implementation. + return true; + } + + // TODO: A more detailed check can be implemented in order to cover for parameter types return types, etc.. + // This with the intention to avoid early stops, however this implementation need to be tested extensively in + // order to avoid missing the target due to unexpected formatting mismatch between declaration and GDB representation. + + return false; + } + + private static boolean sameNumberOfArgumets(MIFrame currentFrame, StepIntoSelectionActiveOperation stepOperation) { + int argSizeAdjustment = 0; + MIArg[] args = currentFrame.getArgs(); + if (args.length > 0) { + // GDB may add the argument "this" e.g. in c++ programs + if (args[0].getName().equals("this")) { //$NON-NLS-1$ + argSizeAdjustment = 1; + } + } + + return ((currentFrame.getArgs().length - argSizeAdjustment) == stepOperation.getTargetFunctionDeclaration().getNumberOfParameters()); + } + + public static void missedSelectedTarget(StepIntoSelectionActiveOperation stepOperation) { + final String functionName = stepOperation.getTargetFunctionDeclaration().getElementName(); + IStatus status = new Status(IStatus.INFO, GdbPlugin.PLUGIN_ID, IGdbDebugConstants.STATUS_HANDLER_CODE, Messages.StepIntoSelection + "\n" + NLS.bind(Messages.StepIntoSelection_Execution_did_not_enter_function, functionName), null); //$NON-NLS-1$ + IStatusHandler statusHandler = DebugPlugin.getDefault().getStatusHandler(status); + if (statusHandler != null) { + try { + statusHandler.handleStatus(status, null); + } catch (CoreException ex) { + GdbPlugin.getDefault().getLog().log(ex.getStatus()); + } + } + } + +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java index c8fa3ba586b..d8bbebf4277 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java @@ -9,6 +9,7 @@ * Wind River Systems - initial API and implementation * Ericsson AB - Modified for additional functionality * Nokia - create and use backend service. + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; @@ -19,7 +20,9 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import org.eclipse.cdt.core.model.IFunctionDeclaration; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +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; @@ -29,7 +32,11 @@ import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IRunControl2; +import org.eclipse.cdt.dsf.debug.service.IRunControl3; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.internal.service.control.StepIntoSelectionActiveOperation; +import org.eclipse.cdt.dsf.gdb.internal.service.control.StepIntoSelectionUtils; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext; @@ -46,6 +53,7 @@ import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadExitEvent; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; 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.mi.service.command.output.MIStackInfoDepthInfo; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.IStatus; @@ -80,13 +88,15 @@ public class GDBRunControl extends MIRunControl { private IGDBBackend fGdb; private IMIProcesses fProcService; private CommandFactory fCommandFactory; + private ICommandControlService fConnection; // Record list of execution contexts private IExecutionDMContext[] fOldExecutionCtxts; private RunToLineActiveOperation fRunToLineActiveOperation = null; - + private StepIntoSelectionActiveOperation fStepInToSelectionActiveOperation = null; + public GDBRunControl(DsfSession session) { super(session); } @@ -106,9 +116,11 @@ public class GDBRunControl extends MIRunControl { fGdb = getServicesTracker().getService(IGDBBackend.class); fProcService = getServicesTracker().getService(IMIProcesses.class); fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); + fConnection = getServicesTracker().getService(ICommandControlService.class); register(new String[]{IRunControl.class.getName(), IRunControl2.class.getName(), + IRunControl3.class.getName(), IMIRunControl.class.getName(), MIRunControl.class.getName(), GDBRunControl.class.getName()}, new Hashtable<String,String>()); @@ -332,6 +344,7 @@ public class GDBRunControl extends MIRunControl { getConnection().queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {bpId}), new DataRequestMonitor<MIInfo>(getExecutor(), null)); fRunToLineActiveOperation = null; + fStepInToSelectionActiveOperation = null; super.handleFailure(); } @@ -361,13 +374,26 @@ public class GDBRunControl extends MIRunControl { getConnection().queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {bpId}), new DataRequestMonitor<MIInfo>(getExecutor(), null)); fRunToLineActiveOperation = null; + fStepInToSelectionActiveOperation = null; } } /** @since 2.0 */ @Override @DsfServiceEventHandler - public void eventDispatched(final MIStoppedEvent e) { + public void eventDispatched(final MIStoppedEvent e) { + if (processRunToLineStoppedEvent(e)) { + // If RunToLine is not completed + return; + } + + if (!processStepIntoSelection(e)) { + //Step into Selection is not in progress broadcast the stop event + super.eventDispatched(e); + } + } + + private boolean processRunToLineStoppedEvent(final MIStoppedEvent e) { if (fRunToLineActiveOperation != null) { int bpId = 0; if (e instanceof MIBreakpointHitEvent) { @@ -407,7 +433,7 @@ public class GDBRunControl extends MIRunControl { new DataRequestMonitor<MIInfo>(getExecutor(), null)); // Don't send the stop event since we are resuming again. - return; + return true; } else { // Stopped at another breakpoint that we should not skip. // Or got an interrupt signal from a suspend command. @@ -423,11 +449,119 @@ public class GDBRunControl extends MIRunControl { getConnection().queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {fRunToLineActiveOperation.getBreakointId()}), new DataRequestMonitor<MIInfo>(getExecutor(), null)); fRunToLineActiveOperation = null; + fStepInToSelectionActiveOperation = null; } } } + + return false; + } + + private boolean processStepIntoSelection(final MIStoppedEvent e) { + if (fStepInToSelectionActiveOperation == null) { + return false; + } + + // First check if it is the right thread that stopped + final IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (fStepInToSelectionActiveOperation.getThreadContext().equals(threadDmc)) { + final MIFrame frame = e.getFrame(); + + assert(fStepInToSelectionActiveOperation.getLine() == frame.getLine()); + assert(fRunToLineActiveOperation == null); + + if (fStepInToSelectionActiveOperation.getRunToLineFrame() == null) { + // Shall now be at the runToline location + fStepInToSelectionActiveOperation.setRunToLineFrame(frame); + } + + // Step - Not at the right place just yet + // Initiate an async call chain parent + getStackDepth(threadDmc, new DataRequestMonitor<Integer>(getExecutor(), null) { + private int originalStackDepth = fStepInToSelectionActiveOperation.getOriginalStackDepth(); + + @Override + protected void handleSuccess() { + int frameDepth = getStackDepth(); + + if (frameDepth > originalStackDepth) { + //shall be true as this is using stepinto step type vs instruction stepinto + assert(frameDepth == originalStackDepth + 1); + + // Check for a match + if (StepIntoSelectionUtils.sameSignature(frame, fStepInToSelectionActiveOperation)) { + // Hit !! + stopStepIntoSelection(e); + return; + } + + // Located deeper in the stack, Shall continue step / search + // Step return + continueStepping(e, StepType.STEP_RETURN); + } else if (frameDepth == originalStackDepth) { + // Continue step / search as long as + // this is the starting base line for the search + String currentLocation = frame.getFile() + ":" + frame.getLine(); //$NON-NLS-1$ + String searchLineLocation = fStepInToSelectionActiveOperation.getFileLocation(); + if (currentLocation.equals(searchLineLocation)) { + continueStepping(e, StepType.STEP_INTO); + } else { + // We have moved to a line + // different from the base + // search line i.e. missed the + // target function !! + StepIntoSelectionUtils.missedSelectedTarget(fStepInToSelectionActiveOperation); + stopStepIntoSelection(e); + } + } else { + // missed the target point + StepIntoSelectionUtils.missedSelectedTarget(fStepInToSelectionActiveOperation); } + } + + @Override + protected void handleFailure() { + // log error + if (getStatus() != null) { + GdbPlugin.getDefault().getLog().log(getStatus()); + } + + stopStepIntoSelection(e); + } + + private int getStackDepth() { + Integer stackDepth = null; + if (isSuccess() && getData() != null) { + stackDepth = getData(); + // This is the base frame, the original stack depth shall be updated + if (frame == fStepInToSelectionActiveOperation.getRunToLineFrame()) { + fStepInToSelectionActiveOperation.setOriginalStackDepth(stackDepth); + originalStackDepth = stackDepth; + } + } - super.eventDispatched(e); + if (stackDepth == null) { + // Unsuccessful resolution of stack depth, default to same stack depth to detect a change of line within the original frame + return fStepInToSelectionActiveOperation.getOriginalStackDepth(); + } + + return stackDepth.intValue(); + } + }); + + //Processing step into selection + return true; + } + + //All threads stopped, however outside the scope of the step into selection context + //We need to abort the step into selection and broadcast the stop + fStepInToSelectionActiveOperation = null; + return false; + } + + private void stopStepIntoSelection(final MIStoppedEvent e) { + fStepInToSelectionActiveOperation = null; + // Need to broadcast the stop + super.eventDispatched(e); } /** @@ -435,5 +569,134 @@ public class GDBRunControl extends MIRunControl { */ protected int getInterruptTimeout() { return IGDBBackend.INTERRUPT_TIMEOUT_DEFAULT; - } + } + + private void continueStepping(final MIStoppedEvent event, StepType steptype) { + step(fStepInToSelectionActiveOperation.getThreadContext(), steptype, false, new RequestMonitor(getExecutor(), null) { + @Override + protected void handleFailure() { + // log error + if (getStatus() != null) { + GdbPlugin.getDefault().getLog().log(getStatus()); + } + + stopStepIntoSelection(event); + } + }); + } + + // ------------------------------------------------------------------------ + // Step into Selection + // ------------------------------------------------------------------------ + private void stepIntoSelection(final IExecutionDMContext context, final int baseLine, final String baseLineLocation, final boolean skipBreakpoints, final IFunctionDeclaration targetFunction, + final RequestMonitor rm) { + + assert context != null; + + final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (dmc == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + if (!doCanResume(dmc)) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + if (fLatestEvent == null || !(fLatestEvent instanceof SuspendedEvent)) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given context: " + context + " invalid suspended event.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + SuspendedEvent suspendedEvent = (SuspendedEvent) fLatestEvent; + final MIFrame currentFrame = suspendedEvent.getMIEvent().getFrame(); + if (currentFrame == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given event: " + suspendedEvent + " with invalid frame.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + getStackDepth(dmc, new DataRequestMonitor<Integer>(getExecutor(), rm) { + @Override + public void handleSuccess() { + if (getData() != null) { + final int framesSize = getData().intValue(); + + // make sure the operation is removed upon + // failure detection + final RequestMonitor rms = new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleFailure() { + fStepInToSelectionActiveOperation = null; + super.handleFailure(); + } + }; + + if ((currentFrame.getFile() + ":" + currentFrame.getLine()).endsWith(baseLineLocation)) { //$NON-NLS-1$ + // Save the step into selection information + fStepInToSelectionActiveOperation = new StepIntoSelectionActiveOperation(dmc, baseLine, targetFunction, framesSize, + currentFrame); + // Ready to step into a function selected + // within a current line + step(dmc, StepType.STEP_INTO, rms); + } else { + // Save the step into selection information + fStepInToSelectionActiveOperation = new StepIntoSelectionActiveOperation(dmc, baseLine, targetFunction, framesSize, null); + // Pointing to a line different than the current line + // Needs to RunToLine before stepping to the selection + runToLocation(dmc, baseLineLocation, skipBreakpoints, rms); + } + } else { + rm.done(); + } + } + }); + } + + /** + * @since 4.2 + */ + @Override + public void canStepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber, IFunctionDeclaration selectedFunction, DataRequestMonitor<Boolean> rm) { + canStep(context, StepType.STEP_INTO, rm); + } + + /** + * @since 4.2 + */ + @Override + public void stepIntoSelection(final IExecutionDMContext context, String sourceFile, final int lineNumber, final boolean skipBreakpoints, final IFunctionDeclaration selectedFunction, final RequestMonitor rm) { + determineDebuggerPath(context, sourceFile, new ImmediateDataRequestMonitor<String>(rm) { + @Override + protected void handleSuccess() { + stepIntoSelection(context, lineNumber, getData() + ":" + Integer.toString(lineNumber), skipBreakpoints, selectedFunction, rm); //$NON-NLS-1$ + } + }); + } + + /** + * Help method used when the stopped event has not been broadcasted e.g. in the middle of step into selection + * + * @param dmc + * @param rm + */ + private void getStackDepth(final IMIExecutionDMContext dmc, final DataRequestMonitor<Integer> rm) { + if (dmc != null) { + fConnection.queueCommand(fCommandFactory.createMIStackInfoDepth(dmc), new DataRequestMonitor<MIStackInfoDepthInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getData().getDepth()); + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ + rm.done(); + } + } + } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java index a3d72580739..b4361367d53 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2012 Wind River Systems and others. + * Copyright (c) 2006, 2013 Wind River Systems 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 @@ -10,6 +10,7 @@ * Ericsson AB - Modified for handling of multiple threads * Indel AG - [369622] fixed moveToLine using MinGW * Marc Khouzam (Ericsson) - Support for operations on multiple execution contexts (bug 330974) + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; @@ -25,6 +26,7 @@ import java.util.Map; import java.util.Set; import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.core.model.IFunctionDeclaration; import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; @@ -51,6 +53,7 @@ import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IRunControl2; +import org.eclipse.cdt.dsf.debug.service.IRunControl3; import org.eclipse.cdt.dsf.debug.service.ISourceLookup; import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; @@ -59,6 +62,8 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.internal.service.command.events.MITracepointSelectedEvent; +import org.eclipse.cdt.dsf.gdb.internal.service.control.StepIntoSelectionActiveOperation; +import org.eclipse.cdt.dsf.gdb.internal.service.control.StepIntoSelectionUtils; import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; @@ -87,7 +92,9 @@ import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadCreatedEvent; import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadExitEvent; import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointTriggerEvent; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; +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.mi.service.command.output.MIStackInfoDepthInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIThread; import org.eclipse.cdt.dsf.mi.service.command.output.MIThreadInfoInfo; import org.eclipse.cdt.dsf.service.AbstractDsfService; @@ -111,8 +118,11 @@ import org.osgi.framework.BundleContext; * sync with the service state. * @since 1.1 */ -public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunControl, IMultiRunControl, ICachingService -{ +public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunControl, IMultiRunControl, ICachingService, IRunControl3 { + // ///////////////////////////////////////////////////////////////////////// + // CONSTANTS + // ///////////////////////////////////////////////////////////////////////// + @Immutable private static class ExecutionData implements IExecutionDMData2 { private final StateChangeReason fReason; @@ -295,6 +305,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo boolean fSuspended = false; boolean fResumePending = false; boolean fStepping = false; + RunControlEvent<IExecutionDMContext, ?> fLatestEvent = null; /** * What caused the state change. E.g., a signal was thrown. @@ -336,7 +347,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo public boolean shouldSkipBreakpoints() { return fSkipBreakpoints; } } - /////////////////////////////////////////////////////////////////////////// + // ///////////////////////////////////////////////////////////////////////// // MIRunControlNS /////////////////////////////////////////////////////////////////////////// @@ -350,6 +361,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo protected Map<IMIExecutionDMContext, MIThreadRunState> fThreadRunStates = new HashMap<IMIExecutionDMContext, MIThreadRunState>(); private RunToLineActiveOperation fRunToLineActiveOperation = null; + + private StepIntoSelectionActiveOperation fStepInToSelectionActiveOperation = null; /** @since 4.0 */ protected RunToLineActiveOperation getRunToLineActiveOperation() { @@ -404,7 +417,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo register(new String[]{ IRunControl.class.getName(), IRunControl2.class.getName(), IMIRunControl.class.getName(), - IMultiRunControl.class.getName() }, + IMultiRunControl.class.getName(), + IRunControl3.class.getName()}, new Hashtable<String,String>()); fConnection = getServicesTracker().getService(ICommandControlService.class); fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); @@ -712,6 +726,10 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo @Override public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) { + step(context, stepType, true, rm); + } + + private void step(IExecutionDMContext context, StepType stepType, boolean checkCanResume, final RequestMonitor rm) { assert context != null; @@ -722,9 +740,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo return; } - if (!doCanResume(dmc)) { - rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, - "Cannot resume context", null)); //$NON-NLS-1$ + if (checkCanResume && !doCanResume(dmc)) { + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$ return; } @@ -839,6 +856,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {bpId}), new DataRequestMonitor<MIInfo>(getExecutor(), null)); fRunToLineActiveOperation = null; + fStepInToSelectionActiveOperation = null; super.handleFailure(); } @@ -849,9 +867,87 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo } // ------------------------------------------------------------------------ - // Resume at location + // Step into Selection // ------------------------------------------------------------------------ + private void stepIntoSelection(final IExecutionDMContext context, final int baseLine, final String baseLineLocation, final boolean skipBreakpoints, final IFunctionDeclaration targetFunction, + final RequestMonitor rm) { + + assert context != null; + + final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (dmc == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + if (!doCanResume(dmc)) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + MIThreadRunState threadState = fThreadRunStates.get(dmc); + if (threadState == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given context: " + context + " can't be found.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + if (threadState.fLatestEvent == null || !(threadState.fLatestEvent instanceof SuspendedEvent)) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given context: " + context + " invalid suspended event.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + SuspendedEvent suspendedEvent = (SuspendedEvent) threadState.fLatestEvent; + final MIFrame currentFrame = suspendedEvent.getMIEvent().getFrame(); + if (currentFrame == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given event: " + suspendedEvent + " invalid frame in suspended event.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + getStackDepth(dmc, new DataRequestMonitor<Integer>(getExecutor(), rm) { + @Override + public void handleSuccess() { + if (getData() != null) { + final int framesSize = getData().intValue(); + + // make sure the operation is removed upon + // failure detection + final RequestMonitor rms = new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleFailure() { + fStepInToSelectionActiveOperation = null; + super.handleFailure(); + } + }; + if ((currentFrame.getFile() + ":" + currentFrame.getLine()).endsWith(baseLineLocation)) { //$NON-NLS-1$ + // Save the step into selection information + fStepInToSelectionActiveOperation = new StepIntoSelectionActiveOperation(dmc, baseLine, targetFunction, framesSize, + currentFrame); + // Ready to step into a function selected + // within a current line + step(dmc, StepType.STEP_INTO, rms); + } else { + // Save the step into selection information + fStepInToSelectionActiveOperation = new StepIntoSelectionActiveOperation(dmc, baseLine, targetFunction, framesSize, null); + // Pointing to a line different than the current line + // Needs to RunToLine before stepping to the selection + runToLocation(dmc, baseLineLocation, skipBreakpoints, rms); + } + } else { + rm.done(); + } + } + }); + } + + // ------------------------------------------------------------------------ + // Resume at location + // ------------------------------------------------------------------------ private void resumeAtLocation(IExecutionDMContext context, String location, RequestMonitor rm) { assert context != null; @@ -958,6 +1054,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo threadState.fStateChangeReason = reason; threadState.fStateChangeDetails = null; // we have no details of interest for a resume threadState.fStepping = isStepping; + threadState.fLatestEvent = event; } private void updateThreadState(IMIExecutionDMContext context, SuspendedEvent event) { @@ -971,7 +1068,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo threadState.fResumePending = false; threadState.fStepping = false; threadState.fStateChangeReason = reason; - threadState.fStateChangeDetails = event.getDetails(); + threadState.fStateChangeDetails = event.getDetails(); + threadState.fLatestEvent = event; } /* ****************************************************************************** @@ -1439,89 +1537,225 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo */ @DsfServiceEventHandler public void eventDispatched(final MIStoppedEvent e) { - if (fRunToLineActiveOperation != null) { - // First check if it is the right thread that stopped - IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); - if (fRunToLineActiveOperation.getThreadContext().equals(threadDmc)) { - int bpId = 0; - if (e instanceof MIBreakpointHitEvent) { - bpId = ((MIBreakpointHitEvent)e).getNumber(); - } - String fileLocation = e.getFrame().getFile() + ":" + e.getFrame().getLine(); //$NON-NLS-1$ - String addrLocation = e.getFrame().getAddress(); - // 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 <MULTIPLE>.) 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! - if (fileLocation.equals(fRunToLineActiveOperation.getFileLocation()) || - addrLocation.equals(fRunToLineActiveOperation.getAddrLocation()) || - bpId == fRunToLineActiveOperation.getBreakointId()) { - // We stopped at the right place. All is well. - fRunToLineActiveOperation = null; - } else { - // The right thread stopped but not at the right place yet - if (fRunToLineActiveOperation.shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) { - fConnection.queueCommand( - fCommandFactory.createMIExecContinue(fRunToLineActiveOperation.getThreadContext()), - new DataRequestMonitor<MIInfo>(getExecutor(), null)); - - // Don't send the stop event since we are resuming again. - return; - } else { - // Stopped for any other reasons. Just remove our temporary one - // since we don't want it to hit later - // - // Note that in Non-stop, we don't cancel a run-to-line when a new - // breakpoint is inserted. This is because the new breakpoint could - // be for another thread altogether and should not affect the current thread. - IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(), - IBreakpointsTargetDMContext.class); - - fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {fRunToLineActiveOperation.getBreakointId()}), - new DataRequestMonitor<MIInfo>(getExecutor(), null)); - fRunToLineActiveOperation = null; - } - } - } - } - + if (processRunToLineStoppedEvent(e)) { + // If RunToLine is not completed + return; + } + + if (!processStepIntoSelection(e)) { + //Step into Selection is not in progress + broadcastStop(e); + } + } + + private void broadcastStop(final MIStoppedEvent e) { IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); - if (e instanceof MISignalEvent && fDisableNextSignalEventDmcSet.remove(threadDmc)) { + if (e instanceof MISignalEvent && fDisableNextSignalEventDmcSet.remove(threadDmc)) { fSilencedSignalEventMap.put(threadDmc, e); - // Don't broadcast the stopped event return; } + + IDMEvent<?> event = null; + MIBreakpointDMContext bp = null; + if (e instanceof MIBreakpointHitEvent) { + int bpId = ((MIBreakpointHitEvent) e).getNumber(); + IBreakpointsTargetDMContext bpsTarget = DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class); + if (bpsTarget != null && bpId >= 0) { + bp = new MIBreakpointDMContext(getSession().getId(), new IDMContext[] { bpsTarget }, bpId); + event = new BreakpointHitEvent(e.getDMContext(), (MIBreakpointHitEvent) e, bp); + } + } + if (event == null) { + event = new SuspendedEvent(e.getDMContext(), e); + } + + getSession().dispatchEvent(event, getProperties()); + } + + private boolean processStepIntoSelection(final MIStoppedEvent e) { + if (fStepInToSelectionActiveOperation == null) { + return false; + } - IDMEvent<?> event = null; - MIBreakpointDMContext bp = null; - if (e instanceof MIBreakpointHitEvent) { - int bpId = ((MIBreakpointHitEvent)e).getNumber(); - IBreakpointsTargetDMContext bpsTarget = DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class); - if (bpsTarget != null && bpId >= 0) { - bp = new MIBreakpointDMContext(getSession().getId(), new IDMContext[] {bpsTarget}, bpId); - event = new BreakpointHitEvent(e.getDMContext(), (MIBreakpointHitEvent)e, bp); - } - } - if (event == null) { - event = new SuspendedEvent(e.getDMContext(), e); - } - - getSession().dispatchEvent(event, getProperties()); + // First check if it is the right thread that stopped + final IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (fStepInToSelectionActiveOperation.getThreadContext().equals(threadDmc)) { + final MIFrame frame = e.getFrame(); + + assert(fRunToLineActiveOperation == null); + + if (fStepInToSelectionActiveOperation.getRunToLineFrame() == null) { + assert(fStepInToSelectionActiveOperation.getLine() == frame.getLine()); + // Shall now be at the runToline location + fStepInToSelectionActiveOperation.setRunToLineFrame(frame); + } + + // Step - Not at the right place just yet + // Initiate an async call chain parent + getStackDepth(threadDmc, new DataRequestMonitor<Integer>(getExecutor(), null) { + private int originalStackDepth = fStepInToSelectionActiveOperation.getOriginalStackDepth(); + + @Override + protected void handleSuccess() { + int frameDepth = getStackDepth(); + + if (frameDepth > originalStackDepth) { + //shall be true as this is using stepinto step type vs instruction stepinto + assert(frameDepth == originalStackDepth + 1); + + // Check for a match + if (StepIntoSelectionUtils.sameSignature(frame, fStepInToSelectionActiveOperation)) { + // Hit !! + stopStepIntoSelection(e); + return; + } + + // Located deeper in the stack, Shall continue step / search + // Step return + continueStepping(e, StepType.STEP_RETURN); + } else if (frameDepth == originalStackDepth) { + // Continue step / search as long as + // this is the starting base line for the search + String currentLocation = frame.getFile() + ":" + frame.getLine(); //$NON-NLS-1$ + String searchLineLocation = fStepInToSelectionActiveOperation.getFileLocation(); + if (currentLocation.equals(searchLineLocation)) { + continueStepping(e, StepType.STEP_INTO); + } else { + // We have moved to a line + // different from the base + // search line i.e. missed the + // target function !! + StepIntoSelectionUtils.missedSelectedTarget(fStepInToSelectionActiveOperation); + stopStepIntoSelection(e); + } + } else { + // missed the target point + StepIntoSelectionUtils.missedSelectedTarget(fStepInToSelectionActiveOperation); + } + } + + @Override + protected void handleFailure() { + // log error + if (getStatus() != null) { + GdbPlugin.getDefault().getLog().log(getStatus()); + } + + stopStepIntoSelection(e); + } + + private int getStackDepth() { + Integer stackDepth = null; + if (isSuccess() && getData() != null) { + stackDepth = getData(); + // This is the base frame, the original stack depth shall be updated + if (frame == fStepInToSelectionActiveOperation.getRunToLineFrame()) { + fStepInToSelectionActiveOperation.setOriginalStackDepth(stackDepth); + originalStackDepth = stackDepth; + } + } + + if (stackDepth == null) { + // Unsuccessful resolution of stack depth, default to same stack depth to detect a change of line within the original frame + return fStepInToSelectionActiveOperation.getOriginalStackDepth(); + } + + return stackDepth.intValue(); + } + }); + + //Processing step into selection + return true; + } + + //The thread related to this event is outside the scope of the step into selection context + return false; } + private void stopStepIntoSelection(final MIStoppedEvent e) { + fStepInToSelectionActiveOperation = null; + // Need to broadcast the stop + broadcastStop(e); + } - /** - * @nooverride This method is not intended to be re-implemented or extended by clients. - * @noreference This method is not intended to be referenced by clients. - */ + private void continueStepping(final MIStoppedEvent event, StepType steptype) { + step(fStepInToSelectionActiveOperation.getThreadContext(), steptype, false, new RequestMonitor(getExecutor(), null) { + @Override + protected void handleFailure() { + // log error + if (getStatus() != null) { + GdbPlugin.getDefault().getLog().log(getStatus()); + } + + stopStepIntoSelection(event); + } + }); + } + + private boolean processRunToLineStoppedEvent(final MIStoppedEvent e) { + if (fRunToLineActiveOperation == null) { + return false; + } + + // First check if it is the right thread that stopped + IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (fRunToLineActiveOperation.getThreadContext().equals(threadDmc)) { + int bpId = 0; + if (e instanceof MIBreakpointHitEvent) { + bpId = ((MIBreakpointHitEvent) e).getNumber(); + } + + String fileLocation = e.getFrame().getFile() + ":" + e.getFrame().getLine(); //$NON-NLS-1$ + String addrLocation = e.getFrame().getAddress(); + + // 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 <MULTIPLE>.) 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! + if (fileLocation.equals(fRunToLineActiveOperation.getFileLocation()) || addrLocation.equals(fRunToLineActiveOperation.getAddrLocation()) + || bpId == fRunToLineActiveOperation.getBreakointId()) { + // We stopped at the right place. All is well. + // Run to line completed + fRunToLineActiveOperation = null; + } else { + // The right thread stopped but not at the right place yet + if (fRunToLineActiveOperation.shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) { + fConnection.queueCommand(fCommandFactory.createMIExecContinue(fRunToLineActiveOperation.getThreadContext()), new DataRequestMonitor<MIInfo>(getExecutor(), null)); + + // Continue i.e. Don't send the stop event since we are + // resuming again. + return true; + } else { + // Stopped for any other reasons. Just remove our temporary one + // since we don't want it to hit later + // + // Note that in Non-stop, we don't cancel a run-to-line when a new + // breakpoint is inserted. This is because the new breakpoint could + // be for another thread altogether and should not affect the current thread. + IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(), IBreakpointsTargetDMContext.class); + + fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] { fRunToLineActiveOperation.getBreakointId() }), new DataRequestMonitor<MIInfo>(getExecutor(), null)); + fRunToLineActiveOperation = null; + fStepInToSelectionActiveOperation = null; + } + } + } + + return false; + } + + /** + * @nooverride This method is not intended to be re-implemented or extended by clients. + * @noreference This method is not intended to be referenced by clients. + */ @DsfServiceEventHandler public void eventDispatched(final MIThreadCreatedEvent e) { IContainerDMContext containerDmc = e.getDMContext(); @@ -1620,6 +1854,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo new DataRequestMonitor<MIInfo>(getExecutor(), null)); fRunToLineActiveOperation = null; } + fStepInToSelectionActiveOperation = null; } /** @@ -2209,4 +2444,46 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo } return execDmcForOperationList; } + + /** + * @since 4.2 + */ + @Override + public void canStepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber, IFunctionDeclaration selectedFunction, DataRequestMonitor<Boolean> rm) { + canStep(context, StepType.STEP_INTO, rm); + } + + /** + * @since 4.2 + */ + @Override + public void stepIntoSelection(final IExecutionDMContext context, String sourceFile, final int lineNumber, final boolean skipBreakpoints, final IFunctionDeclaration selectedFunction, final RequestMonitor rm) { + determineDebuggerPath(context, sourceFile, new ImmediateDataRequestMonitor<String>(rm) { + @Override + protected void handleSuccess() { + stepIntoSelection(context, lineNumber, getData() + ":" + Integer.toString(lineNumber), skipBreakpoints, selectedFunction, rm); //$NON-NLS-1$ + } + }); + } + + /** + * Help method used when the stopped event has not been broadcasted e.g. in the middle of step into selection + * + * @param dmc + * @param rm + */ + private void getStackDepth(final IMIExecutionDMContext dmc, final DataRequestMonitor<Integer> rm) { + if (dmc != null) { + fConnection.queueCommand(fCommandFactory.createMIStackInfoDepth(dmc), new DataRequestMonitor<MIStackInfoDepthInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getData().getDepth()); + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ + rm.done(); + } + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java index de72f05ae9b..e5cc1412f58 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2012 Wind River Systems and others. + * Copyright (c) 2006, 2013 Wind River Systems 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 @@ -11,6 +11,7 @@ * Vladimir Prus (Mentor Graphics) - Add proper stop reason for step return (Bug 362274) * Indel AG - [369622] fixed moveToLine using MinGW * Marc Khouzam (Ericsson) - Make each thread an IDisassemblyDMContext (bug 352748) + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service; @@ -19,6 +20,7 @@ import java.util.LinkedList; import java.util.Map; import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.core.model.IFunctionDeclaration; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; @@ -41,6 +43,7 @@ import org.eclipse.cdt.dsf.debug.service.IBreakpointsExtension.IBreakpointHitDME import org.eclipse.cdt.dsf.debug.service.ICachingService; import org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext; import org.eclipse.cdt.dsf.debug.service.IProcesses; +import org.eclipse.cdt.dsf.debug.service.IRunControl3; import org.eclipse.cdt.dsf.debug.service.ISourceLookup; import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; @@ -96,7 +99,7 @@ import org.osgi.framework.BundleContext; * state. * @since 3.0 */ -public class MIRunControl extends AbstractDsfService implements IMIRunControl, ICachingService +public class MIRunControl extends AbstractDsfService implements IMIRunControl, ICachingService, IRunControl3 { private static class MIExecutionDMC extends AbstractDMContext implements IMIExecutionDMContext, IDisassemblyDMContext { @@ -375,6 +378,10 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I private boolean fResumePending = false; private boolean fStepping = false; private boolean fTerminated = false; + /** + * @since 4.2 + */ + protected RunControlEvent<IExecutionDMContext, ?> fLatestEvent = null; /** @@ -411,7 +418,7 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I super(session); } - @Override + @Override public void initialize(final RequestMonitor rm) { super.initialize( new ImmediateRequestMonitor(rm) { @@ -593,6 +600,8 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I fStateChangeReason = e.getReason(); fStateChangeDetails = null; // we have no details of interest for a resume fMICommandCache.setContextAvailable(e.getDMContext(), false); + fLatestEvent = e; + //fStateChangeTriggeringContext = e.getTriggeringContext(); if (e.getReason().equals(StateChangeReason.STEP)) { fStepping = true; @@ -615,7 +624,8 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I ? e.getTriggeringContexts()[0] : null; fSuspended = true; fStepping = false; - + fLatestEvent = e; + fResumePending = false; } @@ -780,7 +790,14 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I } @Override - public void step(final IExecutionDMContext context, StepType stepType, final RequestMonitor rm) { + public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) { + step(context, stepType, true, rm); + } + + /** + * @since 4.2 + */ + protected void step(final IExecutionDMContext context, StepType stepType, boolean checkCanResume, final RequestMonitor rm) { assert context != null; IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); @@ -790,7 +807,7 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I return; } - if (!doCanResume(context)) { + if (checkCanResume && !doCanResume(context)) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$ rm.done(); return; @@ -1594,8 +1611,9 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I * @param dmc A context that can be used to obtain the sourcelookup context. * @param hostPath The path of the file on the host, which must be converted. * @param rm The result of the conversion. + * @since 4.2 */ - private void determineDebuggerPath(IDMContext dmc, String hostPath, final DataRequestMonitor<String> rm) + protected void determineDebuggerPath(IDMContext dmc, String hostPath, final DataRequestMonitor<String> rm) { ISourceLookup sourceLookup = getServicesTracker().getService(ISourceLookup.class); ISourceLookupDMContext srcDmc = DMContexts.getAncestorOfType(dmc, ISourceLookupDMContext.class); @@ -1615,4 +1633,22 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I } }); } + + /** + * @since 4.2 + */ + @Override + public void canStepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber, IFunctionDeclaration selectedFunction, DataRequestMonitor<Boolean> rm) { + rm.done(false); + } + + /** + * @since 4.2 + */ + @Override + public void stepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber, boolean skipBreakpoints, IFunctionDeclaration selectedFunction, RequestMonitor rm) { + IStatus status = new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Step Into Selection not supported", null); //$NON-NLS-1$ + rm.done(status); + } + } diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Artifact.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Artifact.cc new file mode 100644 index 00000000000..7e98cbf6be9 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Artifact.cc @@ -0,0 +1,49 @@ + +using namespace std; + +#include<string> +//#include<> + +//The 'Component' node +class Artifact { +public: + Artifact(string name) { + fName = name; + fParent = NULL; + } + + //Exercising Polymorphysm + virtual void print() = 0; + virtual string toString() = 0; + virtual void print(char& padc) = 0; + virtual string toString(char& padc) = 0; + + string getName() { + return fName; + } + + string getLocation() { + return fPath + "/" + fName; + } + + virtual void setParent(Artifact &parent) { + fPath = parent.getLocation(); + fParent = &parent; + } + + void deleteParent() { + fPath = ""; + fParent = NULL; + } + + virtual ~Artifact() { + } + +protected: + string fName; + string fPath; + Artifact* fParent; + +private: + Artifact(); +}; diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Composite.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Composite.cc new file mode 100644 index 00000000000..dae86028134 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Composite.cc @@ -0,0 +1,210 @@ +/* + * Composite Pattern + */ +#include<iostream> +#include<string> +#include<vector> +#include "Leaf.cc" + +using namespace std; + +//The 'Composite' node +class CompositeNode: public Artifact { +public: + CompositeNode(string name) : + Artifact(name) { + } + + void Add(Artifact* child) { + child->setParent(*this); + fChildren.push_back(child); + } + + void setParent(Artifact &parent) { + fPath = parent.getLocation(); + fParent = &parent; + + //Refresh the parent information path to all children + vector<Artifact*>::iterator it = fChildren.begin(); + while (it != fChildren.end()) { + Artifact* child = *it; + child->setParent(*this); + ++it; + } + } + + void Remove(Artifact* child) { + child->deleteParent(); + vector<Artifact*>::iterator it = fChildren.begin(); + while (it != fChildren.end()) { + if (*it == child) { + delete child; + fChildren.erase(it); + break; + } + ++it; + } + + } + + void print() { + cout << getLocation() << endl; + + vector<Artifact*>::iterator it = fChildren.begin(); + while (it != fChildren.end()) { + (*it)->print(); + ++it; + } + } + + void print(char& cpad) { + string padding(fPath.length(), cpad); + cout << padding << "+ " << fName << endl; + + vector<Artifact*>::iterator it = fChildren.begin(); + while (it != fChildren.end()) { + (*it)->print(cpad); + ++it; + } + } + + string toString() { + string strAccumulator(getLocation() + "\n"); + + vector<Artifact*>::iterator it = fChildren.begin(); + while (it != fChildren.end()) { + strAccumulator.append((*it)->toString()); + ++it; + } + + return strAccumulator; + } + + string toString(char& cpad) { + string strAccumulation(fPath.length(), cpad); + strAccumulation.append("+ " + fName + "\n"); + + vector<Artifact*>::iterator it = fChildren.begin(); + while (it != fChildren.end()) { + strAccumulation.append((*it)->toString(cpad)); + ++it; + } + + return strAccumulation; + } + + virtual int getArtifactsSize() { + return fChildren.size(); + } + + virtual Artifact* getArtifact(int index) { + if (index < fChildren.size()) { + return fChildren.at(index); + } + + else + return 0; + } + + virtual Artifact* getArtifact(string description) { + vector<Artifact*>::iterator it = fChildren.begin(); + while (it != fChildren.end()) { + if ((*it)->getName().compare(description)) { + return *it; + } + ++it; + } + + return 0; + } + + virtual ~CompositeNode() { + while (!fChildren.empty()) { + vector<Artifact*>::iterator it = fChildren.begin(); + delete *it; + fChildren.erase(it); + } + } + +private: + CompositeNode(); + vector<Artifact*> fChildren; +}; + +//The Main method +int main() { + //Create a tree root + CompositeNode* root = new CompositeNode("Dogs"); + + //Create composite nodes + CompositeNode* comp = new CompositeNode("Companion"); + comp->Add(new LeafNode("Puddle")); + comp->Add(new LeafNode("Bichon")); + + CompositeNode* sport = new CompositeNode("Guardian"); + sport->Add(new LeafNode("Boxer")); + sport->Add(new LeafNode("Rottweiler")); + sport->Add(new LeafNode("Mastiff")); + + //Create a Branch + CompositeNode* gun = new CompositeNode("Gun"); + gun->Add(new LeafNode("Cocker")); + gun->Add(new LeafNode("Pointer")); + gun->Add(new LeafNode("Golden Retriever")); + + CompositeNode* herd = new CompositeNode("Herding"); + herd->Add(new LeafNode("Cattle dog")); + herd->Add(new LeafNode("Sheepdog")); + + CompositeNode* north = new CompositeNode("Northern"); + north->Add(new LeafNode("Akita")); + north->Add(new LeafNode("Chow Chow")); + + CompositeNode* hound = new CompositeNode("Hound"); + hound->Add(new LeafNode("Basset Hound")); + hound->Add(new LeafNode("Beagle")); + + CompositeNode* terrier = new CompositeNode("Terrier"); + terrier->Add(new LeafNode("Bull Terrier")); + terrier->Add(new LeafNode("Border Terrier")); + + //Create some leaf nodes + LeafNode* pe1 = new LeafNode("German Shepperd"); + LeafNode* pe2 = new LeafNode("Great Dane"); + + //Add nodes to start from the same root + root->Add(comp); + root->Add(sport); + root->Add(gun); + root->Add(herd); + root->Add(north); + root->Add(hound); + root->Add(terrier); + //Add leaf nodes to root + root->Add(pe1); + root->Add(pe2); + + char cpad = '-'; + char cpad2 = '_'; + //Test stub + toString variants + if (root->getArtifactsSize() > 0 + && (root->getArtifact(0) != 0 && (root->getArtifact("Bichon") != 0))) { + string sout = root->getArtifact(0)->toString() + "\n" + root->getArtifact(1)->toString(cpad2); + cout << sout << endl; + } + + //Test Remove primitive elements + root->Remove(pe1); + root->Remove(pe2); + + //Test Print variants + root->getArtifact(2)->print(); root->getArtifact(3)->print(cpad); + + //Test toString all + cout << "\n\nAll Tree\n" + root->toString(cpad); + + //delete the allocated memory + delete root; + + return 0; +} diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Leaf.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Leaf.cc new file mode 100644 index 00000000000..bc53da4ef34 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Leaf.cc @@ -0,0 +1,38 @@ +#include<iostream> +#include<string> +#include "Artifact.cc" + + +//The 'Leaf' class +class LeafNode: public Artifact { +public: + LeafNode(string name) : + Artifact(name) { + } + + void print() { + cout << getLocation() << endl; + } + + void print(char& cpad) { + string padding(fPath.length(), cpad); + cout << padding << " " << fName << endl; + } + + + string toString() { + return getLocation() + "\n"; + } + + string toString(char& cpad) { + string padding(fPath.length(), cpad); + string rstr = padding + " " + fName + "\n"; + return rstr; + } + + virtual ~LeafNode() { + } + +private: + LeafNode(); +}; diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java index be375f9c9c1..b64c80f21f8 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2012 Ericsson and others. + * Copyright (c) 2007, 2013 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 @@ -8,6 +8,7 @@ * Contributors: * Ericsson - Initial Implementation * Marc Khouzam (Ericsson) - Add support to receive multiple events + * Alvaro Sanchez-Leon (Ericsson) - Add filter out and wait for a given type of event *******************************************************************************/ package org.eclipse.cdt.tests.dsf.gdb.framework; @@ -94,6 +95,30 @@ public class ServiceEventWaitor<V> { } } + /** + * Will wait and discard events that are not either of the specified type or a subtype + * It will stop and return the first one found or exit after the specified timeout + * + * @param type - The parent type of an acceptable event + * @param timeout the maximum time to wait in milliseconds to wait for a specified event + */ + @SuppressWarnings("unchecked") + public synchronized <T extends V> T waitForEvent(Class<T> type, int timeout) throws Exception { + long startMs = System.currentTimeMillis(); + //The Specified Event received or Timeout exception will exit the loop + while (true) { + int timeRemaining = (int) (timeout - (System.currentTimeMillis() - startMs)); + if (timeRemaining > 0) { + V sevent = waitForEvent(timeRemaining); + if (type.isAssignableFrom(sevent.getClass())) { + return (T) sevent; + } + } else { + throw new Exception("Timed out waiting for ServiceEvent: " + type.getName()); + } + } + } + /* * Block until 'timeout' or the expected event occurs. The expected event is * specified at construction time. @@ -163,7 +188,10 @@ public class ServiceEventWaitor<V> { } } - return fEventQueue.remove(0); + V vevent = fEventQueue.remove(0); + + + return vevent; } /* @@ -177,6 +205,8 @@ public class ServiceEventWaitor<V> { fEventQueue.add(event); notifyAll(); } + } else { + System.out.println("NOT QUEUEING: SevericeEventWaitor: Class: " + fEventTypeClass.getName() + " is NOT assignable from event class: " + event.getClass()); } } } diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java index 5b00c8877b2..2497c8243a8 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2011 Ericsson and others. + * Copyright (c) 2009, 2013 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 @@ -40,6 +40,7 @@ import org.junit.runners.Suite; PostMortemCoreTest.class, CommandTimeoutTest.class, Suite_Sessionless_Tests.class, + StepIntoSelectionTest.class, /* Add your suite class here */ }) diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/StepIntoSelectionTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/StepIntoSelectionTest.java new file mode 100644 index 00000000000..92a5cf2a1df --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/StepIntoSelectionTest.java @@ -0,0 +1,395 @@ +/******************************************************************************* + * Copyright (c) 2013 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 + * + * Contributors: + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) + *******************************************************************************/ +package org.eclipse.cdt.tests.dsf.gdb.tests; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import javax.naming.OperationNotSupportedException; + +import org.eclipse.cdt.core.model.IFunctionDeclaration; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; +import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl3; +import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData; +import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; +import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; +import org.eclipse.cdt.dsf.mi.service.IMIProcesses; +import org.eclipse.cdt.dsf.mi.service.MIProcesses; +import org.eclipse.cdt.dsf.mi.service.command.events.MILocationReachedEvent; +import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; +import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.internal.core.model.FunctionDeclaration; +import org.eclipse.cdt.tests.dsf.gdb.framework.AsyncCompletionWaitor; +import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner; +import org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase; +import org.eclipse.cdt.tests.dsf.gdb.framework.ServiceEventWaitor; +import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil; +import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests Non Stop GDB RunControl "Step into Selection feature" + * + */ +@SuppressWarnings("restriction") +@RunWith(BackgroundRunner.class) +public class StepIntoSelectionTest extends BaseTestCase { + + private DsfServicesTracker fServicesTracker; + + private IGDBControl fGDBCtrl; + private IRunControl3 fRunCtrl; + + private IContainerDMContext fContainerDmc; + private IExecutionDMContext fThreadExecDmc; + + /* + * Path to executable + */ + private static final String EXEC_PATH = "data/launch/bin/"; + + /* + * Name of the executable + */ + private static final String BIN_COMPOSITE = "Composite.exe"; + + // Composite Locations + private static final String SRC_COMPOSITE = "Composite.cc"; + private static final int COMPOSITE_GETARTIFACTSIZE_LINE_1 = 97; + private static final int COMPOSITE_GETARTIFACT_LINE_1 = 101; + private static final int COMPOSITE_MAIN_LINE_S5 = 89; + private static final int COMPOSITE_MAIN_LINE_M1 = 190; + private static final int COMPOSITE_MAIN_LINE_M2 = 191; + private static final int COMPOSITE_MAIN_LINE_L1 = 192; + private static final int COMPOSITE_MAIN_LINE_L2 = 197; + private static final int COMPOSITE_MAIN_LINE_L3 = 201; + private static final int COMPOSITE_MAIN_LINE_L4 = 204; + private static final int COMPOSITE_TOSTRING_LINE_1 = 72; + private static final int COMPOSITE_TOSTRING_C_LINE_1 = 84; + private static final String COMPOSITE_GETARTIFACTSIZE = "getArtifactsSize"; + private static final String COMPOSITE_GETARTIFACT = "getArtifact"; + private static final String COMPOSITE_TOSTRING = "toString"; + + // Artifact Locations + private static final String ARTIFACT_GETLOCATION = "getLocation"; + private static final int ARTIFACT_GETLOCATION_LINE_1 = 26; + + // Leaf Locations + private static final String SRC_LEAF = "Leaf.cc"; + private static final int LEAF_PRINT_LINE_1 = 14; + + //Target Functions + private final static FunctionDeclaration funcCompGetArtifactSize = new FunctionDeclaration(null, COMPOSITE_GETARTIFACTSIZE); + private final static FunctionDeclaration funcCompGetArtifact_i = new FunctionDeclaration(null, COMPOSITE_GETARTIFACT); + private final static FunctionDeclaration funcArtifactGetLocation = new FunctionDeclaration(null, ARTIFACT_GETLOCATION); + private final static FunctionDeclaration funcCompToString = new FunctionDeclaration(null, COMPOSITE_TOSTRING); + private final static FunctionDeclaration funcCompToString_c = new FunctionDeclaration(null, COMPOSITE_TOSTRING); + + static { + funcCompGetArtifact_i.setParameterTypes(new String[]{"int"}); + funcCompToString_c.setParameterTypes(new String[]{"Char&"}); + } + + class ResultContext { + MIStoppedEvent fEvent = null; + IExecutionDMContext fContext = null; + + public ResultContext(MIStoppedEvent event, IExecutionDMContext context) { + this.fEvent = event; + this.fContext = context; + } + + public MIStoppedEvent getEvent() { + return fEvent; + } + + public IExecutionDMContext getContext() { + return fContext; + } + } + + @Override + public void doBeforeTest() throws Exception { + super.doBeforeTest(); + + final DsfSession session = getGDBLaunch().getSession(); + Runnable runnable = new Runnable() { + @Override + public void run() { + fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), session.getId()); + fGDBCtrl = fServicesTracker.getService(IGDBControl.class); + + IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); + IProcessDMContext procDmc = procService.createProcessContext(fGDBCtrl.getContext(), MIProcesses.UNIQUE_GROUP_ID); + fContainerDmc = procService.createContainerContext(procDmc, MIProcesses.UNIQUE_GROUP_ID); + IThreadDMContext threadDmc = procService.createThreadContext(procDmc, "1"); + fThreadExecDmc = procService.createExecutionContext(fContainerDmc, threadDmc, "1"); + + fRunCtrl = fServicesTracker.getService(IRunControl3.class); + } + }; + session.getExecutor().submit(runnable).get(); + } + + @Override + public void doAfterTest() throws Exception { + super.doAfterTest(); + + fServicesTracker.dispose(); + } + + @Override + protected void setLaunchAttributes() { + super.setLaunchAttributes(); + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EXEC_PATH + BIN_COMPOSITE); + setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true); + } + + private IExecutionDMContext gdbRunToStartLine(String sourceName, int targetLine, ServiceEventWaitor<MIStoppedEvent> waitor) throws Throwable { + // run gdb to the specified line an resolve the execution context where the MI signal events are being processed + SyncUtil.runToLine(fThreadExecDmc, sourceName, Integer.toString(targetLine), true); + MILocationReachedEvent locEvent = waitor.waitForEvent(MILocationReachedEvent.class, TestsPlugin.massageTimeout(500)); + return locEvent.getDMContext(); + } + + private MIStoppedEvent getLastEvent(ServiceEventWaitor<MIStoppedEvent> gdbStopListener) { + // Fetch the last stopped event as stepping into selection needs to step several times. + MIStoppedEvent event = null; + // Run until Timeout exception i.e. no more events in the queue + try { + while (true) { + // Wait or fetch the next stopped event in the queue + event = gdbStopListener.waitForEvent(MIStoppedEvent.class, TestsPlugin.massageTimeout(500)); + } + } catch (Exception e) { + assertTrue("Exception: " + e.getMessage(), e.getMessage().contains("Timed out")); + } + + return event; + } + + private void validateLocation(IExecutionDMContext exeContext, MIFrame frame, String funcName) throws Throwable { + // Validate that the frame received is at the specified location + assertTrue(frame.getFunction().endsWith(funcName)); + + // Validate that GDB is in sync at the specified location + IFrameDMData gdbFrame = SyncUtil.getFrameData(exeContext, 0); + assertTrue(gdbFrame.getFunction().endsWith(funcName)); + } + + private void checkGdbIsSuspended() throws Throwable { + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + final IContainerDMContext containerDmc = SyncUtil.getContainerContext(); + + // Execution shall be suspended + fRunCtrl.getExecutor().submit(new Runnable() { + @Override + public void run() { + wait.setReturnInfo(fRunCtrl.isSuspended(containerDmc)); + wait.waitFinished(); + } + }); + + wait.waitUntilDone(TestsPlugin.massageTimeout(5000)); + assertTrue("Target is running. It should have been suspended", (Boolean) wait.getReturnInfo()); + + wait.waitReset(); + } + + private void triggerRunToLine(final IExecutionDMContext exeContext, final String sourceName, final int targetLine) throws InterruptedException { + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + fRunCtrl.getExecutor().submit(new Runnable() { + @Override + public void run() { + fRunCtrl.runToLine(exeContext, sourceName, targetLine, true, new RequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(TestsPlugin.massageTimeout(10000)); + wait.waitReset(); + } + + private void triggerStepIntoSelection(final IExecutionDMContext exeContext, final String sourceName, final int targetLine, final IFunctionDeclaration function, final boolean skipBreakPoints) throws InterruptedException { + final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + final OperationNotSupportedException[] exception = new OperationNotSupportedException[1]; + // Trigger Stepping into a specified 'function' on the current line + fRunCtrl.getExecutor().submit(new Runnable() { + @Override + public void run() { + fRunCtrl.stepIntoSelection(exeContext, sourceName, targetLine, skipBreakPoints, function, new RequestMonitor(fRunCtrl.getExecutor(), null) { + @Override + protected void handleCompleted() { + wait.waitFinished(getStatus()); + } + }); + } + }); + + wait.waitUntilDone(TestsPlugin.massageTimeout(10000)); + wait.waitReset(); + + if (exception[0] != null) { + fail("Step into selection failed: " + exception[0].getMessage()); + } + + } + + private ResultContext runToLine(IExecutionDMContext exeContext, String sourceName, int runToLine) throws Throwable { + DsfSession session = getGDBLaunch().getSession(); + + ServiceEventWaitor<MIStoppedEvent> gdbStopListener = new ServiceEventWaitor<MIStoppedEvent>(session, MIStoppedEvent.class); + + // Trigger Run to line + triggerRunToLine(exeContext, sourceName, runToLine); + + // Fetch the last stopped event as stepping into selection needs to step several times. + MIStoppedEvent event = gdbStopListener.waitForEvent(MIStoppedEvent.class, TestsPlugin.massageTimeout(500)); + + assertNotNull(event); + + // Validate that the last stopped frame received is at the specified location + MIFrame frame = event.getFrame(); + assertTrue(frame.getLine() == runToLine); + return new ResultContext(event, exeContext); + } + + private ResultContext stepIntoSelectionBase(String sourceName, int runToLine, IFunctionDeclaration targetFunction) throws Throwable { + return stepIntoSelectionBase(sourceName, runToLine, targetFunction, true, true, null); + } + + private ResultContext stepIntoSelectionBase(String sourceName, int runToLine, IFunctionDeclaration targetFunction, boolean validateLocation, boolean skipBreakPoints, IExecutionDMContext dmc) throws Throwable { + DsfSession session = getGDBLaunch().getSession(); + + ServiceEventWaitor<MIStoppedEvent> gdbStopListener = new ServiceEventWaitor<MIStoppedEvent>(session, MIStoppedEvent.class); + + final IExecutionDMContext exeContext; + if (dmc == null) { + exeContext = gdbRunToStartLine(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_M1, gdbStopListener); + } else { + exeContext = dmc; + } + + // Run to an initial line an resolve the execution context where the MI signal events are being processed + assertNotNull(exeContext); + + // Trigger Stepping into a specified 'function' and several lines below the current one + triggerStepIntoSelection(exeContext, sourceName, runToLine, targetFunction, skipBreakPoints); + + // Fetch the last stopped event as stepping into selection needs to step several times. + MIStoppedEvent event = getLastEvent(gdbStopListener); + assertNotNull(event); + + // Validate that the last stopped frame received is at the specified location + MIFrame frame = event.getFrame(); + + if (validateLocation) { + validateLocation(exeContext, frame, targetFunction.getElementName()); + } + + checkGdbIsSuspended(); + + return new ResultContext(event, exeContext); + } + + @Test + public void stepIntoSelection() throws Throwable { + ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_M1, funcCompGetArtifactSize); + int currentLine = result.getEvent().getFrame().getLine(); + assertTrue(currentLine == COMPOSITE_GETARTIFACTSIZE_LINE_1); + } + + @Test + public void stepIntoSelectionWithRunToLine() throws Throwable { + ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_M2, funcCompGetArtifact_i); + int currentLine = result.getEvent().getFrame().getLine(); + assertTrue(currentLine == COMPOSITE_GETARTIFACT_LINE_1); + } + + @Test + public void withSelectedLineOnDifferentFile() throws Throwable { + ResultContext result = stepIntoSelectionBase(SRC_LEAF, LEAF_PRINT_LINE_1, funcArtifactGetLocation); + int currentLine = result.getEvent().getFrame().getLine(); + assertTrue(currentLine == ARTIFACT_GETLOCATION_LINE_1); + } + + /** + * A break point is found before reaching search line + * + * @throws Throwable + */ + @Test + public void doNotSkipBreakPoints() throws Throwable { + // insert a break point before the run to line + SyncUtil.addBreakpoint(SRC_COMPOSITE + ":" + COMPOSITE_MAIN_LINE_L2); + //trigger step into selection skip break points is set to false + ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L4, funcCompToString_c, false, false, null); + MIStoppedEvent event = result.getEvent(); + int currentLine = event.getFrame().getLine(); + //validate location, it shall not reach the step to selection line but the break point line instead. + assertTrue(currentLine == COMPOSITE_MAIN_LINE_L2); + //Make sure the step to selection operation is no longer active by triggering a second run to line before the step into selection line + result = runToLine(result.getContext(), SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L3); + event = result.getEvent(); + currentLine = event.getFrame().getLine(); + //validate location, did not reached the step to selection line but the break point + assertTrue(currentLine == COMPOSITE_MAIN_LINE_L3); + } + + @Test + public void diffMethodByArgsNumber() throws Throwable { + ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L1, funcCompToString_c); + int currentLine = result.getEvent().getFrame().getLine(); + assertTrue(currentLine == COMPOSITE_TOSTRING_C_LINE_1); //first line of toString(char& c) + } + + @Test + public void diffMethodByArgsNumber2() throws Throwable { + ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L1, funcCompToString); + int currentLine = result.getEvent().getFrame().getLine(); + assertTrue(currentLine == COMPOSITE_TOSTRING_LINE_1); //first line of toString() + } + + @Test + public void stepIntoRecursiveMethod() throws Throwable { + //Step to the recursive method + ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L4, funcCompToString_c); + int currentLine = result.getEvent().getFrame().getLine(); + assertTrue(currentLine == COMPOSITE_TOSTRING_C_LINE_1); + + //Move away from the first line of the method to validate a successful recursive return to this location + int offset = 3; + result = runToLine(result.getContext(), SRC_COMPOSITE, COMPOSITE_TOSTRING_C_LINE_1 + offset); + currentLine = result.getEvent().getFrame().getLine(); + assertTrue(currentLine == COMPOSITE_TOSTRING_C_LINE_1 + offset); + + //Step into selection to trigger the recursive call + result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_S5, funcCompToString_c, false, false, result.getContext()); + currentLine = result.getEvent().getFrame().getLine(); + + //Assert going back to the top of the same function + assertTrue(currentLine == COMPOSITE_TOSTRING_C_LINE_1); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/StepIntoSelectionTest_6_8.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/StepIntoSelectionTest_6_8.java new file mode 100644 index 00000000000..5095ab20b99 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/StepIntoSelectionTest_6_8.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2013 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 + * + * Contributors: + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) + *******************************************************************************/ +package org.eclipse.cdt.tests.dsf.gdb.tests.tests_6_8; + +import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; +import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner; +import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants; +import org.eclipse.cdt.tests.dsf.gdb.tests.StepIntoSelectionTest; +import org.junit.runner.RunWith; + +@RunWith(BackgroundRunner.class) +public class StepIntoSelectionTest_6_8 extends StepIntoSelectionTest { + @Override + protected void setGdbVersion() { + setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_6_8); + } + + @Override + protected void setLaunchAttributes() { + super.setLaunchAttributes(); + + setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, false); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java index a5b180b6d80..93330c6a4b9 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java @@ -44,6 +44,7 @@ import org.junit.runners.Suite; PostMortemCoreTest_6_8.class, CommandTimeoutTest_6_8.class, Suite_Sessionless_Tests.class, + StepIntoSelectionTest_6_8.class, /* Add your test class here */ }) diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/StepIntoSelectionTest_7_0_NS.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/StepIntoSelectionTest_7_0_NS.java new file mode 100644 index 00000000000..737a015726a --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/StepIntoSelectionTest_7_0_NS.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2013 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 + * + * Contributors: + * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) + *******************************************************************************/ +package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_0; + +import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; +import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner; +import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants; +import org.eclipse.cdt.tests.dsf.gdb.tests.StepIntoSelectionTest; +import org.junit.runner.RunWith; + +@RunWith(BackgroundRunner.class) +public class StepIntoSelectionTest_7_0_NS extends StepIntoSelectionTest { + @Override + protected void setGdbVersion() { + setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_0); + } + + @Override + protected void setLaunchAttributes() { + super.setLaunchAttributes(); + + setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, false); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java index 7b332907ccb..602c08b397c 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2010 Ericsson and others. + * Copyright (c) 2009, 2013 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 @@ -46,7 +46,9 @@ import org.junit.runners.Suite; PostMortemCoreTest_7_0.class, CommandTimeoutTest_7_0.class, GDBMultiNonStopRunControlTest_7_0.class, - Suite_Sessionless_Tests.class, + Suite_Sessionless_Tests.class, + StepIntoSelectionTest_7_0_NS.class, + /* Add your test class here */ }) |