/*******************************************************************************
* Copyright (c) 2011 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:
* Ericsson - Initial Implementation
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_0;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.CLITraceInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner;
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.tests.ITestConstants;
import org.eclipse.cdt.tests.dsf.gdb.tests.tests_6_8.LaunchConfigurationAndRestartTest_6_8;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(BackgroundRunner.class)
public class LaunchConfigurationAndRestartTest_7_0 extends LaunchConfigurationAndRestartTest_6_8 {
// For the launch config test, we must set the attributes in the @Before method
// instead of the @BeforeClass method. This is because the attributes are overwritten
// by the tests themselves
@Before
public void beforeMethod_7_0() {
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_0);
}
/**
* This test will confirm that we have turned on "pending breakpoints"
* The pending breakpoint setting only affects CLI commands so we have
* to test with one. We don't have classes to set breakpoints using CLI,
* but we do for tracepoints, which is the same for this test.
*
* The pending breakpoint feature only works with tracepoints starting
* with GDB 7.0.
*
* We could run this test before 7.0 but we would have to use a breakpoint
* set using CLI commands.
*/
@Test
public void testPendingBreakpointSetting() throws Throwable {
performLaunch();
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
final IBreakpointsTargetDMContext bpTargetDmc = DMContexts.getAncestorOfType(stoppedEvent.getDMContext(),
IBreakpointsTargetDMContext.class);
Query<MIBreakListInfo> query = new Query<MIBreakListInfo>() {
@Override
protected void execute(final DataRequestMonitor<MIBreakListInfo> rm) {
fGdbControl.queueCommand(
fGdbControl.getCommandFactory().createCLITrace(bpTargetDmc, "invalid", ""),
new DataRequestMonitor<CLITraceInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
fGdbControl.queueCommand(
fGdbControl.getCommandFactory().createMIBreakList(bpTargetDmc),
new DataRequestMonitor<MIBreakListInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
rm.setData(getData());
rm.done();
}
});
}
});
}
};
try {
fExpService.getExecutor().execute(query);
MIBreakListInfo value = query.get(500, TimeUnit.MILLISECONDS);
MIBreakpoint[] bps = value.getMIBreakpoints();
assertTrue("Expected 1 breakpoint but got " + bps.length,
bps.length == 1);
assertTrue("Expending a <PENDING> breakpoint but got one at " + bps[0].getAddress(),
bps[0].getAddress().equals("<PENDING>"));
} catch (InterruptedException e) {
fail(e.getMessage());
} catch (ExecutionException e) {
fail(e.getCause().getMessage());
} catch (TimeoutException e) {
fail(e.getMessage());
}
}
/**
* This test will tell the launch to "stop on main" at method main() with reverse
* debugging enabled. We will verify that the launch stops at main() and that
* reverse debugging is enabled.
*/
@Test
public void testStopAtMainWithReverse() throws Throwable {
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, true);
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, "main");
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, true);
performLaunch();
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
// Make sure we stopped at the first line of main
assertTrue("Expected to stop at main:" + FIRST_LINE_IN_MAIN + " but got " +
stoppedEvent.getFrame().getFunction() + ":" +
Integer.toString(stoppedEvent.getFrame().getLine()),
stoppedEvent.getFrame().getFunction().equals("main") &&
stoppedEvent.getFrame().getLine() == FIRST_LINE_IN_MAIN);
// Step a couple of times and check where we are
final int NUM_STEPS = 3;
stoppedEvent = SyncUtil.step(NUM_STEPS, StepType.STEP_OVER);
assertTrue("Expected to stop at main:" + (FIRST_LINE_IN_MAIN+NUM_STEPS) + " but got " +
stoppedEvent.getFrame().getFunction() + ":" +
Integer.toString(stoppedEvent.getFrame().getLine()),
stoppedEvent.getFrame().getFunction().equals("main") &&
stoppedEvent.getFrame().getLine() == FIRST_LINE_IN_MAIN+NUM_STEPS);
// Now step backwards to make sure reverse was enabled
final ServiceEventWaitor<MIStoppedEvent> eventWaitor =
new ServiceEventWaitor<MIStoppedEvent>(
fSession,
MIStoppedEvent.class);
final int REVERSE_NUM_STEPS = 2;
final IExecutionDMContext execDmc = stoppedEvent.getDMContext();
Query<MIInfo> query = new Query<MIInfo>() {
@Override
protected void execute(DataRequestMonitor<MIInfo> rm) {
fGdbControl.queueCommand(
fGdbControl.getCommandFactory().createMIExecReverseNext(execDmc, REVERSE_NUM_STEPS),
rm);
}
};
try {
fGdbControl.getExecutor().execute(query);
query.get(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
fail(e.getMessage());
} catch (ExecutionException e) {
fail(e.getCause().getMessage());
} catch (TimeoutException e) {
fail(e.getMessage());
}
stoppedEvent = eventWaitor.waitForEvent(1000);
assertTrue("Expected to stop at main:" + (FIRST_LINE_IN_MAIN+NUM_STEPS-REVERSE_NUM_STEPS) + " but got " +
stoppedEvent.getFrame().getFunction() + ":" +
Integer.toString(stoppedEvent.getFrame().getLine()),
stoppedEvent.getFrame().getFunction().equals("main") &&
stoppedEvent.getFrame().getLine() == FIRST_LINE_IN_MAIN+NUM_STEPS-REVERSE_NUM_STEPS);
}
/**
* Repeat the test testStopAtMainWithReverse, but after a restart.
*/
@Test
public void testStopAtMainWithReverseRestart() throws Throwable {
fRestart = true;
testStopAtMainWithReverse();
}
/**
* This test will tell the launch to "stop on main" at method stopAtOther(),
* with reverse debugging enabled. We will then verify that the launch is properly
* stopped at stopAtOther() and that it can go backwards until main() (this will
* confirm that reverse debugging was enabled at the very start).
*/
@Test
public void testStopAtOtherWithReverse() throws Throwable {
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, true);
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, "stopAtOther");
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, true);
performLaunch();
// Wait for the launch to properly complete. This is because with reverse
// the first stopped event does not mean the launch is complete. There will
// be another stopped event
synchronized (this) {
wait(1000);
}
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
// The initial stopped event is not the last stopped event.
// With reverse we have to stop the program, turn on reverse and start it again.
// Let's get the frame where we really are stopped right now.
final IExecutionDMContext execDmc = stoppedEvent.getDMContext();
IFrameDMData frame = SyncUtil.getFrameData(execDmc, 0);
// Make sure we stopped at the first line of main
assertTrue("Expected to stop at stopAtOther but got " +
frame.getFunction(),
frame.getFunction().equals("stopAtOther"));
// Now step backwards all the way to the start to make sure reverse was enabled from the very start
final ServiceEventWaitor<MIStoppedEvent> eventWaitor =
new ServiceEventWaitor<MIStoppedEvent>(
fSession,
MIStoppedEvent.class);
final int REVERSE_NUM_STEPS = 3;
Query<MIInfo> query2 = new Query<MIInfo>() {
@Override
protected void execute(DataRequestMonitor<MIInfo> rm) {
fGdbControl.queueCommand(
fGdbControl.getCommandFactory().createMIExecReverseNext(execDmc, REVERSE_NUM_STEPS),
rm);
}
};
try {
fGdbControl.getExecutor().execute(query2);
query2.get(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
fail(e.getMessage());
} catch (ExecutionException e) {
fail(e.getCause().getMessage());
} catch (TimeoutException e) {
fail(e.getMessage());
}
stoppedEvent = eventWaitor.waitForEvent(1000);
assertTrue("Expected to stop at main:" + (FIRST_LINE_IN_MAIN) + " but got " +
stoppedEvent.getFrame().getFunction() + ":" +
Integer.toString(stoppedEvent.getFrame().getLine()),
stoppedEvent.getFrame().getFunction().equals("main") &&
stoppedEvent.getFrame().getLine() == FIRST_LINE_IN_MAIN);
}
/**
* Repeat the test testStopAtOtherWithReverse, but after a restart.
*/
@Test
public void testStopAtOtherWithReverseRestart() throws Throwable {
fRestart = true;
testStopAtOtherWithReverse();
}
/**
* This test will set a breakpoint at the last line of the program and will tell
* the launch to NOT "stop on main", with reverse debugging enabled. We will
* verify that the first stop is at the last line of the program but that the program
* can run backwards until main() (this will confirm that reverse debugging was
* enabled at the very start).
*/
@Ignore
@Test
public void testNoStopAtMainWithReverse() throws Throwable {
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false);
// Set this one as well to make sure it gets ignored
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, "main");
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, true);
// MUST SET BREAKPOINT AT LAST LINE BUT BEFORE LAUNCH IS STARTED
// MUST SET BREAKPOINT AT LAST LINE BUT BEFORE LAUNCH IS STARTED
// MUST SET BREAKPOINT AT LAST LINE BUT BEFORE LAUNCH IS STARTED
// see testNoStopAtMain()
performLaunch();
// Wait for the launch to properly complete. This is because with reverse
// the first stopped event does not mean the launch is complete. There will
// be another stopped event
synchronized (this) {
wait(1000);
}
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
// The initial stopped event is not the last stopped event.
// With reverse we have to stop the program, turn on reverse and start it again.
// Let's get the frame where we really are stopped right now.
final IExecutionDMContext execDmc = stoppedEvent.getDMContext();
IFrameDMData frame = SyncUtil.getFrameData(execDmc, 0);
// Make sure we stopped at the first line of main
assertTrue("Expected to stop at main:" + LAST_LINE_IN_MAIN + " but got " +
frame.getFunction() + ":" +
Integer.toString(frame.getLine()),
frame.getFunction().equals("main") &&
frame.getLine() == LAST_LINE_IN_MAIN);
// Now step backwards all the way to the start to make sure reverse was enabled from the very start
final ServiceEventWaitor<MIStoppedEvent> eventWaitor =
new ServiceEventWaitor<MIStoppedEvent>(
fSession,
MIStoppedEvent.class);
final int REVERSE_NUM_STEPS = 3;
Query<MIInfo> query2 = new Query<MIInfo>() {
@Override
protected void execute(DataRequestMonitor<MIInfo> rm) {
fGdbControl.queueCommand(
fGdbControl.getCommandFactory().createMIExecReverseNext(execDmc, REVERSE_NUM_STEPS),
rm);
}
};
try {
fGdbControl.getExecutor().execute(query2);
query2.get(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
fail(e.getMessage());
} catch (ExecutionException e) {
fail(e.getCause().getMessage());
} catch (TimeoutException e) {
fail(e.getMessage());
}
stoppedEvent = eventWaitor.waitForEvent(1000);
assertTrue("Expected to stop at main:" + (FIRST_LINE_IN_MAIN) + " but got " +
stoppedEvent.getFrame().getFunction() + ":" +
Integer.toString(stoppedEvent.getFrame().getLine()),
stoppedEvent.getFrame().getFunction().equals("main") &&
stoppedEvent.getFrame().getLine() == FIRST_LINE_IN_MAIN);
}
/**
* Repeat the test testNoStopAtMainWithReverse, but after a restart.
*/
@Ignore
@Test
public void testNoStopAtMainWithReverseRestart() throws Throwable {
fRestart = true;
testNoStopAtMainWithReverse();
}
}