| /******************************************************************************* |
| * 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); |
| } |
| } |