| /******************************************************************************* |
| * Copyright (c) 2013, 2015 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) |
| * Simon Marchi (Ericsson) - Fix atDoubleMethod* tests for older gdb (<= 7.3) |
| *******************************************************************************/ |
| package org.eclipse.cdt.tests.dsf.gdb.tests; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.util.concurrent.TimeUnit; |
| |
| import org.eclipse.cdt.core.model.IFunctionDeclaration; |
| import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; |
| import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; |
| import org.eclipse.cdt.dsf.concurrent.Query; |
| 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.IRunControl.ISuspendedDMEvent; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl3; |
| import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent; |
| 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.BaseParametrizedTestCase; |
| 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; |
| import org.junit.runners.Parameterized; |
| |
| /** |
| * Tests Non Stop GDB RunControl "Step into Selection feature" |
| * |
| */ |
| @SuppressWarnings("restriction") |
| @RunWith(Parameterized.class) |
| public class StepIntoSelectionTest extends BaseParametrizedTestCase { |
| |
| private DsfServicesTracker fServicesTracker; |
| private DsfSession fSession; |
| |
| private IRunControl3 fRunCtrl; |
| |
| private static final String EXEC_NAME = "StepIntoSelectionTestApp.exe"; |
| private static final String SOURCE_NAME = "StepIntoSelectionTestApp.cc"; |
| private static final String HEADER_NAME = "StepIntoSelection.h"; |
| |
| protected int FOO_LINE; |
| protected int BAR_LINE; |
| protected int VALUE_LINE; |
| protected int ADD_WITH_ARG_LINE; |
| protected int ADD_NO_ARG_LINE; |
| |
| protected static final String[] SOURCE_LINE_TAGS = { |
| "FOO_LINE", |
| "BAR_LINE", |
| "ADD_WITH_ARG_LINE", |
| "ADD_NO_ARG_LINE", |
| }; |
| protected static final String[] HEADER_LINE_TAGS = { |
| "VALUE_LINE", |
| }; |
| |
| //Target Functions |
| private final static FunctionDeclaration funcFoo = new FunctionDeclaration(null, "foo"); |
| private final static FunctionDeclaration funcBar = new FunctionDeclaration(null, "bar"); |
| private final static FunctionDeclaration funcRecursive = new FunctionDeclaration(null, "recursiveTest"); |
| private final static FunctionDeclaration funcValue = new FunctionDeclaration(null, "value"); |
| private final static FunctionDeclaration funcAddNoArg = new FunctionDeclaration(null, "add"); |
| private final static FunctionDeclaration funcAddWithArg = new FunctionDeclaration(null, "add"); |
| |
| static { |
| funcBar.setParameterTypes(new String[]{"int"}); |
| funcRecursive.setParameterTypes(new String[]{"int"}); |
| funcAddWithArg.setParameterTypes(new String[]{"int"}); |
| } |
| |
| 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(); |
| |
| Runnable runnable = new Runnable() { |
| @Override |
| public void run() { |
| fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); |
| fRunCtrl = fServicesTracker.getService(IRunControl3.class); |
| } |
| }; |
| fSession = getGDBLaunch().getSession(); |
| fSession.getExecutor().submit(runnable).get(); |
| |
| resolveLineTagLocations(SOURCE_NAME, SOURCE_LINE_TAGS); |
| resolveLineTagLocations(HEADER_NAME, HEADER_LINE_TAGS); |
| |
| FOO_LINE = getLineForTag("FOO_LINE"); |
| BAR_LINE = getLineForTag("BAR_LINE"); |
| VALUE_LINE = getLineForTag("VALUE_LINE"); |
| ADD_WITH_ARG_LINE = getLineForTag("ADD_WITH_ARG_LINE"); |
| ADD_NO_ARG_LINE = getLineForTag("ADD_NO_ARG_LINE"); |
| } |
| |
| @Override |
| public void doAfterTest() throws Exception { |
| super.doAfterTest(); |
| |
| if (fServicesTracker!=null) fServicesTracker.dispose(); |
| } |
| |
| @Override |
| protected void setLaunchAttributes() { |
| super.setLaunchAttributes(); |
| setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EXEC_PATH + EXEC_NAME); |
| } |
| |
| private void validateLocation(ISuspendedDMEvent suspendedEvent, String expectedFunction, |
| String expectedFile, int expectedLine, int expectedDepth) throws Throwable { |
| assertNotNull(suspendedEvent); |
| |
| assertTrue("Expected suspended event to be IMIDMEvent, but it was not.", suspendedEvent instanceof IMIDMEvent); |
| Object miEvent = ((IMIDMEvent)suspendedEvent).getMIEvent(); |
| |
| assertTrue("Expected mi event to be MIStoppedEvent, but it was not.", miEvent instanceof MIStoppedEvent); |
| MIStoppedEvent stoppedEvent = (MIStoppedEvent)miEvent; |
| |
| // Validate that the last stopped frame received is at the specified location |
| MIFrame frame = stoppedEvent.getFrame(); |
| assertTrue("Not inside the expected function. Expected " + |
| expectedFunction + " but got " + |
| frame.getFunction(), |
| frame.getFunction().endsWith(expectedFunction)); |
| assertEquals(expectedLine, frame.getLine()); |
| |
| assertTrue("Not inside the expected file. Expected " + |
| expectedFile + " but got " + frame.getFile(), |
| frame.getFile().endsWith(expectedFile)); |
| |
| int newDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| assertEquals(expectedDepth, newDepth); |
| |
| checkGdbIsSuspended(); |
| } |
| |
| private void checkGdbIsSuspended() throws Throwable { |
| final IContainerDMContext containerDmc = SyncUtil.getContainerContext(); |
| Query<Boolean> query = new Query<Boolean>() { |
| @Override |
| protected void execute(DataRequestMonitor<Boolean> rm) { |
| rm.done(fRunCtrl.isSuspended(containerDmc)); |
| } |
| }; |
| fSession.getExecutor().execute(query); |
| |
| boolean suspended = query.get(TestsPlugin.massageTimeout(5000), TimeUnit.SECONDS); |
| assertTrue("Target is running. It should have been suspended", suspended); |
| } |
| |
| /** |
| * Perform a stepIntoSelection operation and return the SuspendedEvent indicating the |
| * stepInto has been completed. |
| */ |
| private ISuspendedDMEvent triggerStepIntoSelection(final IExecutionDMContext exeContext, |
| final String sourceName, |
| final int targetLine, |
| final IFunctionDeclaration function, |
| final boolean skipBreakPoints) |
| throws Throwable { |
| ServiceEventWaitor<ISuspendedDMEvent> eventWaitor = |
| new ServiceEventWaitor<ISuspendedDMEvent>(fSession, ISuspendedDMEvent.class); |
| |
| Query<Object> query = new Query<Object>() { |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| fRunCtrl.stepIntoSelection(exeContext, sourceName, targetLine, skipBreakPoints, function, rm); |
| } |
| }; |
| fSession.getExecutor().execute(query); |
| query.get(); |
| |
| return eventWaitor.waitForEvent(TestsPlugin.massageTimeout(10000)); |
| } |
| |
| /** |
| * Perform a stepIntoSelection operation and return the SuspendedEvent indicating the |
| * stepInto has been completed. |
| */ |
| private ISuspendedDMEvent triggerRunToLine(final IExecutionDMContext exeContext, |
| final String sourceName, |
| final int targetLine, |
| final boolean skipBreakPoints) |
| throws Throwable { |
| ServiceEventWaitor<ISuspendedDMEvent> eventWaitor = |
| new ServiceEventWaitor<ISuspendedDMEvent>(fSession, ISuspendedDMEvent.class); |
| |
| Query<Object> query = new Query<Object>() { |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| fRunCtrl.runToLine(exeContext, sourceName, targetLine, skipBreakPoints, rm); |
| } |
| }; |
| fSession.getExecutor().execute(query); |
| query.get(); |
| |
| return eventWaitor.waitForEvent(TestsPlugin.massageTimeout(10000)); |
| } |
| |
| /** |
| * This test verifies that we can step into a selection on the same line as where we are currently. |
| */ |
| @Test |
| public void atSameLine() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("sameLineTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcFoo; |
| |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| stoppedEvent.getFrame().getLine(), targetFunction, false); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, FOO_LINE, originalDepth + 1); |
| } |
| |
| /** |
| * This test verifies that we can step into a selection from a later line than where we are currently. |
| */ |
| @Test |
| public void atLaterLine() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("laterLineTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcFoo; |
| int line = stoppedEvent.getFrame().getLine() + 3; // The method to stepInto is three lines below the start of the method |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, false); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, FOO_LINE, originalDepth + 1); |
| } |
| |
| /** |
| * This test verifies that we can step into a selection of a different file. |
| */ |
| @Test |
| public void atLaterLineOnDifferentFile() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("laterLineDifferentFileTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcValue; |
| int line = stoppedEvent.getFrame().getLine() + 1; // The method to stepInto is one line below the start of the method |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, false); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), HEADER_NAME, VALUE_LINE, originalDepth + 1); |
| } |
| |
| /** |
| * This test verifies that we can step into a selection than has two method calls. |
| * We try to step into the deepest call. |
| */ |
| @Test |
| public void atDoubleMethodDeepCall() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("doubleMethodTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcFoo; |
| int line = stoppedEvent.getFrame().getLine() + 1; // The method to stepInto is one line below the start of the method |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, false); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, FOO_LINE, originalDepth + 1); |
| } |
| |
| /** |
| * This test verifies that we can step into a selection than has two method calls. |
| * We try to step into the most shallow call. |
| */ |
| @Test |
| public void atDoubleMethodShalowCall() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("doubleMethodTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcBar; |
| int line = stoppedEvent.getFrame().getLine() + 1; // The method to stepInto is one line below the start of the method |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, false); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, BAR_LINE, originalDepth + 1); |
| } |
| |
| /** |
| * This test verifies that we can step into a recursive method. |
| */ |
| @Test |
| public void recursiveMethod() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("recursiveTest"); |
| int finalLine = stoppedEvent.getFrame().getLine(); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcRecursive; |
| |
| int line = stoppedEvent.getFrame().getLine() + 2; // The method to stepInto is two lines below the start of the method |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, false); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, finalLine, originalDepth + 1); |
| } |
| |
| /** |
| * This test verifies that if we try to step into a selection from an earlier line we will end up |
| * stopping at the first breakpoint that hits. |
| */ |
| @Test |
| public void atPreviousLine() throws Throwable { |
| String functionName = "laterLineTest"; |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation(functionName); |
| int originalLine = stoppedEvent.getFrame().getLine(); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| // Step past the function call |
| stoppedEvent = SyncUtil.step(4, StepType.STEP_OVER); |
| // Set a bp one line below. We will check that this breakpoint hits when a stepInto is done |
| int bpline = originalLine + 4 + 1; |
| SyncUtil.addBreakpoint(Integer.toString(bpline)); |
| |
| FunctionDeclaration targetFunction = funcFoo; |
| int line = originalLine + 3; // The method to stepInto is three lines below the start of the method |
| |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, false); |
| |
| validateLocation(suspendedEvent, functionName, SOURCE_NAME, bpline, originalDepth); |
| } |
| |
| /** |
| * This test verifies that if we try to step into a selection from a later line that we will not reach, we will end up |
| * stopping at the first breakpoint that hits. |
| */ |
| @Test |
| public void atLaterLineThatIsNotHit() throws Throwable { |
| String functionName = "laterLineNotHitTest"; |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation(functionName); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcFoo; |
| int line = stoppedEvent.getFrame().getLine() + 2; // The method to stepInto is two lines below the start of the method |
| // Except we'll never reach it |
| // Set a bp a couple of lines below. We will check that this breakpoint hits and the stepInto is cancelled |
| int bpline = line + 2; |
| SyncUtil.addBreakpoint(Integer.toString(bpline)); |
| |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, false); // Don't skip breakpoints |
| |
| validateLocation(suspendedEvent, functionName, SOURCE_NAME, bpline, originalDepth); |
| |
| // Make sure the step to selection operation is no longer active by triggering a run to line before the step into selection line |
| suspendedEvent = triggerRunToLine(stoppedEvent.getDMContext(), SOURCE_NAME, |
| bpline + 1, false); |
| |
| validateLocation(suspendedEvent, functionName, SOURCE_NAME, bpline + 1, originalDepth); |
| |
| } |
| |
| /** |
| * This test verifies that when specified, we stop at a breakpoint that is hit before the StepIntoSelection |
| * is completed. |
| */ |
| @Test |
| public void atLaterLineStopAtBreakpoint() throws Throwable { |
| String functionName = "laterLineTest"; |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation(functionName); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| int originalLine = stoppedEvent.getFrame().getLine(); |
| |
| // Set a breakpoint before the stepInto line |
| SyncUtil.addBreakpoint(Integer.toString(originalLine+1)); |
| |
| int line = originalLine + 3; // The method to stepInto is three lines below the start of the method |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, funcFoo, false); |
| |
| validateLocation(suspendedEvent, functionName, SOURCE_NAME, originalLine + 1, originalDepth); |
| |
| // Make sure the step to selection operation is no longer active by triggering a run to line before the step into selection line |
| suspendedEvent = triggerRunToLine(stoppedEvent.getDMContext(), SOURCE_NAME, |
| originalLine + 2, false); |
| |
| validateLocation(suspendedEvent, functionName, SOURCE_NAME, originalLine + 2, originalDepth); |
| } |
| |
| /** |
| * This test verifies that when specified, we ignore all breakpoints that are hit before the StepIntoSelection |
| * is completed. |
| */ |
| @Test |
| public void atLaterLineSkipBreakpoints() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("laterLineTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| int originalLine = stoppedEvent.getFrame().getLine(); |
| |
| // Set two breakpoints before the stepInto line |
| SyncUtil.addBreakpoint(Integer.toString(originalLine+1)); |
| SyncUtil.addBreakpoint(Integer.toString(originalLine+2)); |
| |
| int line = originalLine + 3; // The method to stepInto is three lines below the start of the method |
| |
| FunctionDeclaration targetFunction = funcFoo; |
| |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, true); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, FOO_LINE, originalDepth + 1); |
| } |
| |
| private void atDoubleMethodStopAtBreakpointCommon(int foo_line) throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("doubleMethodTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| // Set a breakpoint inside foo, which will hit before our |
| // StepInto is finished |
| SyncUtil.addBreakpoint(Integer.toString(foo_line)); |
| |
| FunctionDeclaration targetFunction = funcBar; |
| int line = stoppedEvent.getFrame().getLine() + 1; // The method to stepInto is one line below the start of the method |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, false); // Set not to skip breakpoints, but it should have no effect |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, BAR_LINE, originalDepth + 1); |
| } |
| |
| /** |
| * This test verifies that we will not stop at a breakpoint if it is in the middle |
| * of the step-in operations when the run-to-line skip breakpoint option is not selected. |
| * |
| * It is only enabled for gdb > 7.3. gdb <= 7.3 generates a stopped event with two |
| * reasons, resulting in two MIStoppedEvent in the step-into-selection machinery. Later |
| * gdbs generate a stopped event with only one reason, as they should. |
| */ |
| @Test |
| public void atDoubleMethodStopAtBreakpointFunctionEntry() throws Throwable { |
| assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_7_4); |
| atDoubleMethodStopAtBreakpointCommon(FOO_LINE); |
| } |
| |
| /** |
| * This test is just like atDoubleMethodStopAtBreakpointFunctionEntry, but avoids placing |
| * the breakpoint at the beginning of foo(). |
| */ |
| @Test |
| public void atDoubleMethodStopAtBreakpoint() throws Throwable { |
| atDoubleMethodStopAtBreakpointCommon(FOO_LINE + 1); |
| } |
| |
| private void atDoubleMethodSkipBreakpointCommon(int foo_line) throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("doubleMethodTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| // Set a breakpoint inside foo, which will hit before our |
| // StepInto is finished |
| SyncUtil.addBreakpoint(Integer.toString(foo_line)); |
| |
| FunctionDeclaration targetFunction = funcBar; |
| int line = stoppedEvent.getFrame().getLine() + 1; // The method to stepInto is one line below the start of the method |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| line, targetFunction, true); // Set skip breakpoints, which should have non impact |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, BAR_LINE, originalDepth + 1); |
| } |
| |
| /** |
| * This test verifies that we will not stop at a breakpoint if it is in the middle |
| * of the step-in operations even if the run-to-line skip breakpoint option is selected. |
| * |
| * It is only enabled for gdb > 7.3. gdb <= 7.3 generates a stopped event with two |
| * reasons, resulting in two MIStoppedEvent in the step-into-selection machinery. Later |
| * gdbs generate a stopped event with only one reason, as they should. |
| */ |
| @Test |
| public void atDoubleMethodSkipBreakpointFunctionEntry() throws Throwable { |
| assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_7_4); |
| atDoubleMethodSkipBreakpointCommon(FOO_LINE); |
| } |
| |
| /** |
| * This test is just like atDoubleMethodSkipBreakpointFunctionEntry, but avoids placing |
| * the breakpoint at the beginning of foo(). |
| */ |
| @Test |
| public void atDoubleMethodSkipBreakpoint() throws Throwable { |
| atDoubleMethodSkipBreakpointCommon(FOO_LINE + 1); |
| } |
| |
| /** |
| * This test verifies that if we have two methods with the same name on the same line, |
| * we properly choose the method with the correct number of arguments based on the |
| * step into selection. |
| */ |
| @Test |
| public void diffMethodByArgsNumber() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("methodWithDiffArgsNumberTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcAddWithArg; |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| stoppedEvent.getFrame().getLine(), targetFunction, false); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, ADD_WITH_ARG_LINE, originalDepth + 1); |
| } |
| |
| @Test |
| public void diffMethodByArgsNumber2() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("methodWithDiffArgsNumberTest"); |
| int originalDepth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| FunctionDeclaration targetFunction = funcAddNoArg; |
| // StepInto the method |
| ISuspendedDMEvent suspendedEvent = triggerStepIntoSelection(stoppedEvent.getDMContext(), SOURCE_NAME, |
| stoppedEvent.getFrame().getLine(), targetFunction, false); |
| |
| validateLocation(suspendedEvent, targetFunction.getElementName(), SOURCE_NAME, ADD_NO_ARG_LINE, originalDepth + 1); |
| } |
| } |