blob: f1aa789b41ebc33ed3a650128bfc38573dcba1a8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2010 Nokia 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:
* Nokia - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.edc.debugger.tests;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
import junit.framework.Assert;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.debug.core.model.ICBreakpoint;
import org.eclipse.cdt.debug.core.model.ICBreakpointType;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Breakpoints;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules;
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ExecutionDMC;
import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
import org.eclipse.cdt.debug.edc.services.IEDCExecutionDMC;
import org.eclipse.cdt.debug.edc.tests.AbstractLaunchTest;
import org.eclipse.cdt.debug.edc.tests.EDCTestPlugin;
import org.eclipse.cdt.debug.edc.tests.TestUtils;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
import org.eclipse.cdt.dsf.debug.service.IStack;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IBreakpoint;
/**
* Test based on live debug session for an x86 application on local host.
* It runs with EDC Windows debugger or EDC Linux debugger.
*/
public abstract class BaseLaunchTest extends AbstractLaunchTest {
private static final String CDT_LOCAL_LAUNCH_TYPE = ICDTLaunchConfigurationConstants.ID_LAUNCH_C_APP;
private static final String EDC_LAUNCH_DELEGATE_LINUX = "org.eclipse.cdt.debug.edc.linux.x86.launchDelegate";
private static final String EDC_LAUNCH_DELEGATE_WINDOWS = "org.eclipse.cdt.debug.edc.windows.localLaunchDelegate";
protected EDCLaunch launch;
protected DsfSession session;
protected ExecutionDMC threadDMC;
protected IFrameDMContext frame;
protected IStack getStackService() {
return null;
}
protected void assertControlIsAt(String fileName,
String functionName, int lineNo) throws Exception {
assertFrameMatches(frame, fileName, functionName, lineNo);
}
protected void assertFrameMatches(final IFrameDMContext frame2, String fileName,
String functionName, int lineNo) throws Exception {
final IStack stackService = getStackService();
assertNotNull(stackService);
Query<IFrameDMData> query = new Query<IFrameDMData>() {
@Override
protected void execute(final DataRequestMonitor<IFrameDMData> drm) {
stackService.getFrameData(frame2, drm);
}
};
session.getExecutor().execute(query);
IFrameDMData fdata = null;
fdata = query.get(5, TimeUnit.SECONDS);
if (fdata == null)
fail("Error getting stack frame data.");
assertNotNull(fdata);
assertNotNull(fdata.getFile());
assertTrue(
"Expected source file is [" + fileName + "] but got [" + fdata.getFile() + "].",
fdata.getFile().contains(fileName));
assertEquals(functionName, fdata.getFunction());
assertEquals(lineNo, fdata.getLine());
}
protected void basicLaunch() throws Exception {
TestUtils.showDebugPerspective();
launch = createLaunch();
assertNotNull(launch);
session = waitForSession(launch);
assertNotNull(session);
IEDCExecutionDMC executionDMC = TestUtils.waitForExecutionDMC(session);
assertNotNull(executionDMC);
threadDMC = TestUtils.waitForSuspendedThread(session);
Assert.assertNotNull(threadDMC);
frame = TestUtils.waitForStackFrame(session, threadDMC);
}
protected EDCLaunch createLaunch() throws Exception {
ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationWorkingCopy configuration = lm.getLaunchConfigurationType(CDT_LOCAL_LAUNCH_TYPE)
.newInstance(null, "EDCTestLaunch");
String exePath = getTestExecutable();
configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, exePath);
// do more configuration.
configureLaunchConfiguration(configuration);
String launchDelegateID = EDC_LAUNCH_DELEGATE_LINUX;
if (Platform.getOS().equals(Platform.OS_WIN32))
launchDelegateID = EDC_LAUNCH_DELEGATE_WINDOWS;
HashSet<String> set = new HashSet<String>();
set.add(ILaunchManager.DEBUG_MODE);
configuration.setPreferredLaunchDelegate(set, launchDelegateID);
return (EDCLaunch) configuration.doSave().launch(ILaunchManager.DEBUG_MODE, new NullProgressMonitor(), true);
}
/**
* Set more settings for the launch configuration so that subclass can do whatever it likes.
*
* @param configuration
*/
protected void configureLaunchConfiguration(
ILaunchConfigurationWorkingCopy configuration) {
if (getStopAtMain()) {
// Make sure it stop at main
configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, true);
configuration.setAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, "main");
}
}
/**
* Get full path of executable file in {plugin}/resources/SymbolFiles folder.
*
* @return a full path
*/
protected boolean getStopAtMain() {
return false;
}
/**
* Get full path of executable file in {plugin}/resources/SymbolFiles folder.
*
* @return a full path
*/
protected String getTestExecutable() {
/*
* String exePath = System.getenv("EXEPATH"); if (exePath == null ||
* !new File(exePath).exists()) throw new
* Exception("EXEPATH env var not set to valid executable to launch!");
*/
String res_folder = null;
try {
res_folder = EDCTestPlugin.projectRelativePath("resources/SymbolFiles");
} catch (Exception e) {
fail("Folder resources/SymbolFiles is missing in the test project.");
}
IPath dataPath = new Path(res_folder);
String exeFileName = getExeFileName();
dataPath = dataPath.append(exeFileName);
return dataPath.toOSString();
}
/**
* Get executable file name without path. The file is supposed to be in
* {plugin}/resources/SymbolFiles folder.
*/
protected String getExeFileName() {
String ret = null;
if (Platform.getOS().equals(Platform.OS_WIN32))
// This is an executable with hard-coded breakpoint (a divide-by-zero statement)
// so that it will suspend by itself after launch.
ret = "BlackFlagMinGW.exe";
else
ret = "BlackFlag_linuxgcc.exe";
return ret;
}
/**
* set a User breakpoint
* - for use when the breakpoint needs to persist or act like a normal breakpoint
* @param Breakpoints breakpoint service
* @param String srcFile
* @param int lineNo
* @throws Exception
*/
protected void removeUserBreakpoint(final Breakpoints breakpointsService,
final IBreakpointDMContext userBPContext) throws Exception {
Query<Object> query = new Query<Object>() {
@Override
protected void execute(final DataRequestMonitor<Object> rm) {
breakpointsService.removeBreakpoint(userBPContext,
new RequestMonitor(session.getExecutor(), rm) {
@Override
protected void handleCompleted() {
rm.done();
}});
}};
session.getExecutor().execute(query);
query.get(5, TimeUnit.SECONDS);
}
/**
* set a temporary breakpoint
* - for use when the breakpoint is no longer necessary after the next suspend
* @param Breakpoints breakpoint service
* @param String srcFile
* @param int lineNo
* @throws Exception
*/
protected void setTempBreakpoint(final Breakpoints bpService,
final String srcFile, final int lineNo) throws Exception {
Query<IBreakpointDMContext> query = new Query<IBreakpoints.IBreakpointDMContext>() {
@Override
protected void execute(
final DataRequestMonitor<IBreakpoints.IBreakpointDMContext> drm) {
Modules modulesService = getDsfServicesTracker(session).getService(Modules.class);
modulesService.getLineAddress(threadDMC, srcFile, lineNo,
new DataRequestMonitor<List<IAddress>>(session.getExecutor(), drm) {
@Override
protected void handleSuccess() {
List<IAddress> addrs = getData();
// IBreakpointsTargetDMContext bt_dmc = DMContexts.getAncestorOfType(executionDMC, IBreakpointsTargetDMContext.class);
bpService.setTempBreakpoint(threadDMC, addrs.get(0),
new RequestMonitor(session.getExecutor(), drm));
}});
}
};
session.getExecutor().execute(query);
query.get(5, TimeUnit.SECONDS);
}
/**
* set a User breakpoint
* - for use when the breakpoint needs to persist or act like a normal breakpoint
* @param Breakpoints breakpoint service
* @param String srcFile
* @param int lineNo
* @throws Exception
*/
protected IBreakpointDMContext setUserBreakpoint(final Breakpoints breakpointsService,
final String srcFile, final int lineNo) throws Exception {
final String coreId = DebugPlugin.getUniqueIdentifier();
final HashMap<String, Object> bkptAttributes = new HashMap<String, Object>();
bkptAttributes.put(IBreakpoint.ID, coreId);
bkptAttributes.put(IBreakpoint.ENABLED, true);
bkptAttributes.put(Breakpoints.BREAKPOINT_TYPE, Breakpoints.BREAKPOINT);
bkptAttributes.put(Breakpoints.BREAKPOINT_SUBTYPE, Breakpoints.LINE_BREAKPOINT);
bkptAttributes.put("lineNumber", lineNo);
bkptAttributes.put(ICBreakpoint.SOURCE_HANDLE, srcFile);
bkptAttributes.put(ICBreakpoint.IGNORE_COUNT, 0);
bkptAttributes.put(ICBreakpoint.INSTALL_COUNT, 1);
bkptAttributes.put(ICBreakpoint.CONDITION, "");
bkptAttributes.put(ICBreakpointType.TYPE, ICBreakpointType.REGULAR);
Query<IBreakpointDMContext> query = new Query<IBreakpointDMContext>() {
@Override
protected void execute(final DataRequestMonitor<IBreakpointDMContext> drm) {
Modules modulesService = getDsfServicesTracker(session).getService(Modules.class);
modulesService.getLineAddress(threadDMC, srcFile, lineNo,
new DataRequestMonitor<List<IAddress>>(session.getExecutor(), drm) {
@Override
protected void handleSuccess() {
List<IAddress> addrs = getData();
bkptAttributes.put(Breakpoints.RUNTIME_ADDRESS, addrs.get(0).toString(0x10));
IBreakpointsTargetDMContext bdmc
= DMContexts.getAncestorOfType(threadDMC, IBreakpointsTargetDMContext.class);
breakpointsService.insertBreakpoint(bdmc, bkptAttributes,
new DataRequestMonitor<IBreakpointDMContext>(session.getExecutor(), drm) {
@Override
protected void handleSuccess() {
drm.setData(getData());
drm.done();
}});
}});
}};
session.getExecutor().execute(query);
IBreakpointDMContext userBreakpoint = query.get(5, TimeUnit.SECONDS);
assertTrue(query.isDone());
assertNotNull(userBreakpoint);
return userBreakpoint;
}
/**
* Wait for a suspend and update suspended thread and frame.
* @param waitForSuspend time to wait for suspend event to be broadcasted.
*
* @throws Exception
*/
protected void updateSuspendedFrame(int waitForSuspend) throws Exception {
assertNotNull(threadDMC);
// Wait some time for the suspend event to get broadcasted.
Thread.sleep(waitForSuspend);
frame = TestUtils.waitForStackFrame(session, threadDMC, 0);
}
/**
* find the address for a given line
*
* @param source
* @param line
* @throws Exception
*/
protected IAddress waitGetLineAddress(final String source, final int line) throws Exception {
Query<IAddress> query = new Query<IAddress>() {
@Override
protected void execute(final DataRequestMonitor<IAddress> drm) {
Modules modulesService = getDsfServicesTracker(session).getService(Modules.class);
modulesService.getLineAddress(threadDMC, source, line,
new DataRequestMonitor<List<IAddress>>(session.getExecutor(), drm) {
@Override
protected void handleSuccess() {
List<IAddress> addrs = getData();
drm.setData(addrs.get(0));
drm.done();
}});
}
};
session.getExecutor().execute(query);
IAddress addr = query.get(5, TimeUnit.SECONDS);
if (addr == null)
fail("Error calling getLineAddress() ");
return addr;
}
/**
* Perform run to line and wait till it's done. Underlying members "thread" and "frame"
* will be updated.
*
* @param fileName
* @param lineNo
* @throws Exception
*/
protected void waitRunToLine(final IRunControl2 runControlService,
final String fileName, final int lineNo) throws Exception {
waitRunToLine(runControlService, fileName, lineNo, 400);
}
protected void waitRunToLine(final IRunControl2 runControlService,
final String fileName, final int lineNo, int waitForSuspend) throws Exception {
Query<IStatus> query = new Query<IStatus>() {
@Override
protected void execute(final DataRequestMonitor<IStatus> drm) {
runControlService.runToLine(threadDMC, fileName, lineNo, false, new RequestMonitor(session.getExecutor(), drm) {
@Override
protected void handleCompleted() {
drm.setData(getStatus());
drm.done();
}});
}
};
session.getExecutor().execute(query);
IStatus status = query.get(15, TimeUnit.SECONDS);
if (status == null || ! status.isOK())
fail("Error in run-to-line: " + (status == null ? "Exception happened." : status.getMessage()));
updateSuspendedFrame(waitForSuspend);
}
}