diff options
author | Umair Sair | 2019-08-18 01:23:03 +0000 |
---|---|---|
committer | Jonah Graham | 2019-08-19 16:43:22 +0000 |
commit | 9d97a364190efb6bf73df45a78772289917cbe54 (patch) | |
tree | 71ea807ad8be433cc249e15b1a1ab33d03817375 | |
parent | 342d0c7b892cd216650a0b17f36c8539f519705a (diff) | |
download | org.eclipse.cdt-9d97a364190efb6bf73df45a78772289917cbe54.tar.gz org.eclipse.cdt-9d97a364190efb6bf73df45a78772289917cbe54.tar.xz org.eclipse.cdt-9d97a364190efb6bf73df45a78772289917cbe54.zip |
Bug 550165: Debugging is stuck when "command aborts" on step return
Adding unit test for MIAsyncErrorProcessor. The test adds breakpoint on
0x0 address and try to continue and step return. It asserts that the
target is in stopped state and error as reason in both cases. Then it
removes all the breakpoints and resumes the target and asserts that
target is in resumed state.
Change-Id: I2e024e0d5f55b4e9464a6f2b7a2b0c78bee4e8e8
Signed-off-by: Umair Sair <umair_sair@hotmail.com>
2 files changed, 220 insertions, 1 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/SuiteGdb.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/SuiteGdb.java index 29c3e7f7030..76ebe71e9f3 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/SuiteGdb.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/SuiteGdb.java @@ -20,6 +20,7 @@ import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.MIRunControlNonStopTargetAvai import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.OperationsWhileTargetIsRunningNonStopTest; import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.StepIntoSelectionNonStopTest; import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.ThreadStackFrameSyncTest; +import org.eclipse.cdt.tests.dsf.mi.service.command.MIAsyncErrorProcessorTests; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -45,7 +46,7 @@ import org.junit.runners.Suite; OperationsWhileTargetIsRunningNonStopTest.class, StepIntoSelectionNonStopTest.class, GDBRemoteTracepointsTest.class, TraceFileTest.class, GDBConsoleSynchronizingTest.class, MIMemoryTest.class, MIDisassemblyTest.class, GDBProcessesTest.class, PostMortemCoreTest.class, CommandTimeoutTest.class, - ThreadStackFrameSyncTest.class, CommandLineArgsTest.class, + ThreadStackFrameSyncTest.class, CommandLineArgsTest.class, MIAsyncErrorProcessorTests.class /* Add your test class here */ }) public class SuiteGdb { diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/mi/service/command/MIAsyncErrorProcessorTests.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/mi/service/command/MIAsyncErrorProcessorTests.java new file mode 100644 index 00000000000..afc903444a8 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/mi/service/command/MIAsyncErrorProcessorTests.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 2019 Mentor Graphics and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Umair Sair (Mentor Graphics) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.tests.dsf.mi.service.command; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMData; +import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType; +import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; +import org.eclipse.cdt.dsf.mi.service.MIRunControl; +import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.tests.dsf.gdb.framework.AsyncCompletionWaitor; +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.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * Tests MIAsyncErrorProcessor for continue and step return command failure + */ +@RunWith(Parameterized.class) +public class MIAsyncErrorProcessorTests extends BaseParametrizedTestCase { + + private static final String EXEC_NAME = "MultiThread.exe"; + + private MIRunControl runControl; + private IGDBControl commandControl; + private IContainerDMContext containerDmc; + + @Override + protected void setLaunchAttributes() { + super.setLaunchAttributes(); + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EXEC_PATH + EXEC_NAME); + } + + @Override + public void doBeforeTest() throws Exception { + assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_7_12); + + super.doBeforeTest(); + + DsfSession session = getGDBLaunch().getSession(); + Runnable runnable = () -> { + DsfServicesTracker servicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), + session.getId()); + assert (servicesTracker != null); + + runControl = servicesTracker.getService(MIRunControl.class); + assert (runControl != null); + + commandControl = servicesTracker.getService(IGDBControl.class); + assert (commandControl != null); + + servicesTracker.dispose(); + }; + + session.getExecutor().submit(runnable).get(); + containerDmc = SyncUtil.getContainerContext(); + + try { + prepareEnvironment(); + } catch (Throwable e) { + throw new Exception(e); + } + } + + private void prepareEnvironment() throws Throwable { + AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + /* + * 1. Confirm that target is suspended initially + */ + assertTrue(runControl.isSuspended(containerDmc)); + + /* + * 2. 'set confirm off' as we'll will be deleting all breakpoints latter using 'del' command + */ + commandControl.queueCommand( + commandControl.getCommandFactory().createMIInterpreterExecConsole(containerDmc, "set confirm off"), + new ImmediateDataRequestMonitor<MIInfo>() { + @Override + public void handleCompleted() { + wait.waitFinished(getStatus()); + } + }); + + wait.waitUntilDone(TestsPlugin.massageTimeout(1000)); + wait.waitReset(); + + /* + * 3. Add breakpoint at ThreadSetName symbol and resume so that we have deeper stack + */ + SyncUtil.addBreakpoint("ThreadSetName"); + performOperationAndWaitForSuspend(SyncUtil::resume); + + /* + * 4. Add breakpoint at 0x0 which will cause continue and step return failure + */ + SyncUtil.addBreakpoint("*0x0", false); + } + + @Test + public void executeContinueTest() throws Throwable { + performOperationAndWaitForSuspend(SyncUtil::resume); + + assertTrue(isTargetStoppedWithError()); + } + + @Test + public void executeStepReturnTest() throws Throwable { + performOperationAndWaitForSuspend(() -> SyncUtil.step(StepType.STEP_RETURN)); + + assertTrue(isTargetStoppedWithError()); + } + + @Test + public void executeContinueTestThenRemoveBreakpointsAndResume() throws Throwable { + executeContinueTest(); + + AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); + + /* + * Remove all breakpoints and resume. Target should be in resumed state now + */ + commandControl.queueCommand( + commandControl.getCommandFactory().createMIInterpreterExecConsole(containerDmc, "del"), + new ImmediateDataRequestMonitor<MIInfo>() { + @Override + public void handleCompleted() { + wait.waitFinished(getStatus()); + } + }); + + wait.waitUntilDone(TestsPlugin.massageTimeout(1000)); + wait.waitReset(); + + SyncUtil.resume(); + + Thread.sleep(1000); + + assertFalse(runControl.isSuspended(containerDmc)); + } + + /** + * Performs the operation and wait for suspend. The operation should be such that the target + * is resumed on running it + * + * @param operation + * an operation that will resume the target + * @throws Throwable + * Any problem while running the operation or waiting for stop event + */ + private void performOperationAndWaitForSuspend(Operation operation) throws Throwable { + ServiceEventWaitor<IContainerResumedDMEvent> resumeEventWaitor = new ServiceEventWaitor<>( + getGDBLaunch().getSession(), IContainerResumedDMEvent.class); + ServiceEventWaitor<MIStoppedEvent> stopEventWaitor = new ServiceEventWaitor<>(getGDBLaunch().getSession(), + MIStoppedEvent.class); + + operation.run(); + + resumeEventWaitor.waitForEvent(TestsPlugin.massageTimeout(1000)); + stopEventWaitor.waitForEvent(TestsPlugin.massageTimeout(1000)); + waitUntil("Waiting for suspend", () -> runControl.isSuspended(containerDmc), TestsPlugin.massageTimeout(1000)); + } + + private boolean isTargetStoppedWithError() throws Exception { + if (!runControl.isSuspended(containerDmc)) + return false; + + Query<Boolean> query = new Query<Boolean>() { + @Override + protected void execute(DataRequestMonitor<Boolean> rm) { + runControl.getExecutionData(containerDmc, new ImmediateDataRequestMonitor<IExecutionDMData>(rm) { + @Override + protected void handleCompleted() { + rm.done(isSuccess() && getData().getStateChangeReason() == StateChangeReason.ERROR); + } + }); + } + }; + + runControl.getExecutor().execute(query); + + return query.get(TestsPlugin.massageTimeout(2000), TimeUnit.MILLISECONDS); + } + + private interface Operation { + void run() throws Throwable; + } +} |