/******************************************************************************* * Copyright (c) 2004, 2010 QNX Software Systems 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: * QNX Software Systems - Initial API and implementation * Anton Leherbauer (Wind River Systems) - bugs 205108, 212632, 224187 * Ken Ryall (Nokia) - bug 188116 *******************************************************************************/ package org.eclipse.cdt.launch.internal; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.IProcessInfo; import org.eclipse.cdt.core.IProcessList; import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.debug.core.CDIDebugModel; import org.eclipse.cdt.debug.core.CDebugUtils; import org.eclipse.cdt.debug.core.ICDIDebugger; import org.eclipse.cdt.debug.core.ICDIDebugger2; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.debug.core.ICDebugConfiguration; import org.eclipse.cdt.debug.core.cdi.CDIException; import org.eclipse.cdt.debug.core.cdi.ICDISession; import org.eclipse.cdt.debug.core.cdi.model.ICDIRuntimeOptions; import org.eclipse.cdt.debug.core.cdi.model.ICDITarget; import org.eclipse.cdt.launch.AbstractCLaunchDelegate; import org.eclipse.cdt.launch.internal.ui.LaunchMessages; import org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin; import org.eclipse.cdt.utils.pty.PTY; import org.eclipse.cdt.utils.spawner.ProcessFactory; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.IStatusHandler; import org.eclipse.debug.core.model.IProcess; /** * The launch configuration delegate for the CDI debugger session types. */ public class LocalCDILaunchDelegate extends AbstractCLaunchDelegate { /* (non-Javadoc) * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor) */ public void launch(ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException { if (monitor == null) { monitor = new NullProgressMonitor(); } if (mode.equals(ILaunchManager.RUN_MODE)) { runLocalApplication(config, launch, monitor); } if (mode.equals(ILaunchManager.DEBUG_MODE)) { launchDebugger(config, launch, monitor); } } private void runLocalApplication(ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor) throws CoreException { monitor.beginTask(LaunchMessages.LocalCDILaunchDelegate_0, 10); if (monitor.isCanceled()) { return; } monitor.worked(1); try { IPath exePath = CDebugUtils.verifyProgramPath(config); File wd = getWorkingDirectory(config); if (wd == null) { wd = new File(System.getProperty("user.home", ".")); //$NON-NLS-1$ //$NON-NLS-2$ } String arguments[] = getProgramArgumentsArray(config); ArrayList command = new ArrayList(1 + arguments.length); command.add(exePath.toOSString()); command.addAll(Arrays.asList(arguments)); String[] commandArray = (String[])command.toArray(new String[command.size()]); boolean usePty = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_USE_TERMINAL, ICDTLaunchConfigurationConstants.USE_TERMINAL_DEFAULT); monitor.worked(2); Process process = exec(commandArray, getEnvironment(config), wd, usePty); monitor.worked(6); DebugPlugin.newProcess(launch, process, renderProcessLabel(commandArray[0])); } finally { monitor.done(); } } private void launchDebugger(ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor) throws CoreException { monitor.beginTask(LaunchMessages.LocalCDILaunchDelegate_1, 10); if (monitor.isCanceled()) { return; } try { String debugMode = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN); if (debugMode.equals(ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN)) { launchLocalDebugSession(config, launch, monitor); } if (debugMode.equals(ICDTLaunchConfigurationConstants.DEBUGGER_MODE_ATTACH)) { launchAttachDebugSession(config, launch, monitor); } if (debugMode.equals(ICDTLaunchConfigurationConstants.DEBUGGER_MODE_CORE)) { launchCoreDebugSession(config, launch, monitor); } } finally { monitor.done(); } } private void launchLocalDebugSession(ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor) throws CoreException { if (monitor.isCanceled()) { return; } monitor.subTask(LaunchMessages.LocalCDILaunchDelegate_2); ICDISession dsession = null; try { IPath exePath = CDebugUtils.verifyProgramPath(config); ICProject project = CDebugUtils.verifyCProject(config); IBinaryObject exeFile = null; if (exePath != null) { exeFile = verifyBinary(project, exePath); } ICDebugConfiguration debugConfig = getDebugConfig(config); setDefaultSourceLocator(launch, config); dsession = createCDISession(config, launch, debugConfig, monitor); monitor.worked(6); setRuntimeOptions(config, dsession); monitor.worked(1); boolean stopInMain = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false); String stopSymbol = null; if (stopInMain) stopSymbol = launch.getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT); ICDITarget[] targets = dsession.getTargets(); for(int i = 0; i < targets.length; i++) { Process process = targets[i].getProcess(); IProcess iprocess = null; if (process != null) { iprocess = DebugPlugin.newProcess(launch, process, renderProcessLabel(exePath.toOSString()), getDefaultProcessMap()); } CDIDebugModel.newDebugTarget(launch, project.getProject(), targets[i], renderTargetLabel(debugConfig), iprocess, exeFile, true, false, stopSymbol, true); } } catch(CoreException e) { try { if (dsession != null) dsession.terminate(); } catch(CDIException e1) { // ignore } throw e; } finally { monitor.done(); } } private void launchAttachDebugSession(ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor) throws CoreException { if (monitor.isCanceled()) { return; } monitor.subTask(LaunchMessages.LocalCDILaunchDelegate_3); ILaunchConfigurationWorkingCopy wc = null; int pid = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_ATTACH_PROCESS_ID, -1); if (pid == -1) { pid = promptForProcessID(config); if (pid == -1) { cancel(LaunchMessages.LocalCDILaunchDelegate_4, ICDTLaunchConfigurationConstants.ERR_NO_PROCESSID); } wc = config.getWorkingCopy(); wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_ATTACH_PROCESS_ID, pid); try { wc.doSave().launch(ILaunchManager.DEBUG_MODE, new SubProgressMonitor(monitor, 9)); } finally { // We need to reset the process id because the working copy will be saved // when the target is terminated wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_ATTACH_PROCESS_ID, (String)null); wc.doSave(); } cancel("", -1); //$NON-NLS-1$ } IPath exePath = CDebugUtils.verifyProgramPath(config); if (exePath == null) { exePath= getProgramPathForPid(pid); } ICProject project = CDebugUtils.verifyCProject(config); IBinaryObject exeFile = null; if (exePath != null) { exeFile = verifyBinary(project, exePath); } ICDebugConfiguration debugConfig = getDebugConfig(config); setDefaultSourceLocator(launch, config); ICDISession dsession = createCDISession(config, launch,debugConfig, monitor); monitor.worked(7); try { ICDITarget[] targets = dsession.getTargets(); for(int i = 0; i < targets.length; i++) { CDIDebugModel.newDebugTarget(launch, project.getProject(), targets[i], renderTargetLabel(debugConfig), null, exeFile, true, true, false); } } catch(CoreException e) { try { dsession.terminate(); } catch(CDIException e1) { // ignore } throw e; } finally { if (wc != null) wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_ATTACH_PROCESS_ID, (String)null); monitor.done(); } } private IPath getProgramPathForPid(int pid) { IProcessList processList= null; try { processList= CCorePlugin.getDefault().getProcessList(); } catch (CoreException exc) { // ignored on purpose } if (processList != null) { IProcessInfo[] pInfos= processList.getProcessList(); for (int i = 0; i < pInfos.length; i++) { IProcessInfo processInfo = pInfos[i]; if (processInfo.getPid() == pid) { final String name= processInfo.getName(); if (name != null) { return new Path(name); } break; } } } return null; } private void launchCoreDebugSession(ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor) throws CoreException { if (monitor.isCanceled()) { return; } monitor.beginTask(LaunchMessages.LocalCDILaunchDelegate_5, 10); ICDISession dsession = null; ILaunchConfigurationWorkingCopy wc = null; ICDebugConfiguration debugConfig = getDebugConfig(config); String path = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, (String)null); if (path == null || path.length() == 0) { ICProject project = CDebugUtils.verifyCProject(config); IPath corefile = promptForCoreFilePath((IProject)project.getResource(), debugConfig); if (corefile == null) { cancel(LaunchMessages.LocalCDILaunchDelegate_6, ICDTLaunchConfigurationConstants.ERR_NO_COREFILE); } File file = new File(corefile.toString()); if (!file.exists() || !file.canRead()) { cancel(LaunchMessages.LocalCDILaunchDelegate_7, ICDTLaunchConfigurationConstants.ERR_NO_COREFILE); } wc = config.getWorkingCopy(); wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, corefile.toString()); wc.launch(ILaunchManager.DEBUG_MODE, new SubProgressMonitor(monitor, 9)); wc.setAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, (String)null); cancel("", -1); //$NON-NLS-1$ } IPath exePath = CDebugUtils.verifyProgramPath(config); ICProject project = CDebugUtils.verifyCProject(config); IBinaryObject exeFile = null; if (exePath != null) { exeFile = verifyBinary(project, exePath); } setDefaultSourceLocator(launch, config); dsession = createCDISession(config, launch, debugConfig, monitor); monitor.worked(7); try { ICDITarget[] targets = dsession.getTargets(); for(int i = 0; i < targets.length; i++) { Process process = targets[i].getProcess(); IProcess iprocess = null; if (process != null) { iprocess = DebugPlugin.newProcess(launch, process, renderProcessLabel(exePath.toOSString()), getDefaultProcessMap()); } CDIDebugModel.newDebugTarget(launch, project.getProject(), targets[i], renderTargetLabel(debugConfig), iprocess, exeFile, true, false, false); } } catch(CoreException e) { try { if (dsession != null) dsession.terminate(); } catch(CDIException e1) { // ignore } throw e; } finally { monitor.done(); } } private ICDISession launchOldDebugSession(ILaunchConfiguration config, ILaunch launch, ICDIDebugger debugger, IProgressMonitor monitor) throws CoreException { IBinaryObject exeFile = null; IPath exePath = CDebugUtils.verifyProgramPath(config); ICProject project = CDebugUtils.verifyCProject(config); if (exePath != null) { exeFile = verifyBinary(project, exePath); } return debugger.createDebuggerSession(launch, exeFile, monitor); } private ICDISession launchDebugSession(ILaunchConfiguration config, ILaunch launch, ICDIDebugger2 debugger, IProgressMonitor monitor) throws CoreException { IPath path = CDebugUtils.verifyProgramPath(config); File exeFile = path != null ? path.toFile() : null; return debugger.createSession(launch, exeFile, monitor); } /* (non-Javadoc) * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#getPluginID() */ protected String getPluginID() { return LaunchUIPlugin.getUniqueIdentifier(); } /** * Performs a runtime exec on the given command line in the context of the * specified working directory, and returns the resulting process. If the * current runtime does not support the specification of a working * directory, the status handler for error code * <code>ERR_WORKING_DIRECTORY_NOT_SUPPORTED</code> is queried to see if * the exec should be re-executed without specifying a working directory. * * @param cmdLine * the command line * @param workingDirectory * the working directory, or <code>null</code> * @return the resulting process or <code>null</code> if the exec is * cancelled * @see Runtime */ protected Process exec(String[] cmdLine, String[] environ, File workingDirectory, boolean usePty) throws CoreException { Process p = null; try { if (workingDirectory == null) { p = ProcessFactory.getFactory().exec(cmdLine, environ); } else { if (usePty && PTY.isSupported()) { p = ProcessFactory.getFactory().exec(cmdLine, environ, workingDirectory, new PTY()); } else { p = ProcessFactory.getFactory().exec(cmdLine, environ, workingDirectory); } } } catch(IOException e) { if (p != null) { p.destroy(); } abort(LaunchMessages.LocalCDILaunchDelegate_8, e, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); } catch(NoSuchMethodError e) { // attempting launches on 1.2.* - no ability to set working // directory IStatus status = new Status(IStatus.ERROR, LaunchUIPlugin.getUniqueIdentifier(), ICDTLaunchConfigurationConstants.ERR_WORKING_DIRECTORY_NOT_SUPPORTED, LaunchMessages.LocalCDILaunchDelegate_9, e); IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler(status); if (handler != null) { Object result = handler.handleStatus(status, this); if (result instanceof Boolean && ((Boolean)result).booleanValue()) { p = exec(cmdLine, environ, null, usePty); } } } return p; } protected int promptForProcessID(ILaunchConfiguration config) throws CoreException { IStatus fPromptStatus = new Status(IStatus.INFO, "org.eclipse.debug.ui", 200, "", null); //$NON-NLS-1$//$NON-NLS-2$ IStatus processPrompt = new Status(IStatus.INFO, "org.eclipse.cdt.launch", 100, "", null); //$NON-NLS-1$//$NON-NLS-2$ // consult a status handler IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(fPromptStatus); if (prompter != null) { Object result = prompter.handleStatus(processPrompt, config); if (result instanceof Integer) { return ((Integer) result).intValue(); } } return -1; } protected IPath promptForCoreFilePath(final IProject project, final ICDebugConfiguration debugConfig) throws CoreException { IStatus fPromptStatus = new Status(IStatus.INFO, "org.eclipse.debug.ui", 200, "", null); //$NON-NLS-1$//$NON-NLS-2$ IStatus processPrompt = new Status(IStatus.INFO, "org.eclipse.cdt.launch", 1001, "", null); //$NON-NLS-1$//$NON-NLS-2$ // consult a status handler IStatusHandler prompter = DebugPlugin.getDefault().getStatusHandler(fPromptStatus); if (prompter != null) { Object result = prompter.handleStatus(processPrompt, new Object[]{ project, debugConfig }); if (result instanceof IPath) { return (IPath) result; } } return null; } /* (non-Javadoc) * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#preLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.core.runtime.IProgressMonitor) */ public boolean preLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor) throws CoreException { // no pre launch check for core file if (mode.equals(ILaunchManager.DEBUG_MODE)) { if (ICDTLaunchConfigurationConstants.DEBUGGER_MODE_CORE.equals(config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN))) return true; } return super.preLaunchCheck(config, mode, monitor); } private void setRuntimeOptions(ILaunchConfiguration config, ICDISession session) throws CoreException { String arguments[] = getProgramArgumentsArray(config); try { ICDITarget[] dtargets = session.getTargets(); for(int i = 0; i < dtargets.length; ++i) { ICDIRuntimeOptions opt = dtargets[i].getRuntimeOptions(); opt.setArguments(arguments); File wd = getWorkingDirectory(config); if (wd != null) { opt.setWorkingDirectory(wd.getAbsolutePath()); } opt.setEnvironment(getEnvironmentAsProperty(config)); } } catch (CDIException e) { abort(LaunchMessages.LocalCDILaunchDelegate_10, e, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); } } private ICDISession createCDISession(ILaunchConfiguration config, ILaunch launch, ICDebugConfiguration debugConfig, IProgressMonitor monitor) throws CoreException { ICDISession session = null; ICDIDebugger debugger = debugConfig.createDebugger(); if (debugger instanceof ICDIDebugger2) session = launchDebugSession(config, launch, (ICDIDebugger2)debugger, monitor); else // support old debugger types session = launchOldDebugSession(config, launch, debugger, monitor); return session; } @Override public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { // Never build for attach. Bug 188116 String debugMode = configuration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN); if (debugMode.equals(ICDTLaunchConfigurationConstants.DEBUGGER_MODE_ATTACH)) return false; return super.buildForLaunch(configuration, mode, monitor); } }