debuggercdi/com.nokia.cdt.debug.launch/src/com/nokia/cdt/internal/debug/launch/NokiaAbstractLaunchDelegate.java
/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.cdt.internal.debug.launch;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.IBinary;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.debug.core.executables.ExecutablesManager;
import org.eclipse.cdt.launch.AbstractCLaunchDelegate;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
import org.eclipse.debug.core.sourcelookup.ISourceContainer;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import com.freescale.cdt.debug.cw.core.cdi.Session;
import com.nokia.carbide.cdt.builder.builder.CarbideCPPBuilder;
import com.nokia.cdt.debug.cw.symbian.SymbianPlugin;
import com.nokia.cdt.debug.cw.symbian.SymbianSourceContainer;
import com.nokia.cdt.debug.cw.symbian.ui.executables.ExecutableTargeted;
import com.nokia.carbide.cpp.debug.kernelaware.OSDataManager;
import com.nokia.cdt.internal.debug.launch.ui.ExecutablesTab;
public abstract class NokiaAbstractLaunchDelegate extends
AbstractCLaunchDelegate {
/**
* [comment_20070318] This is my local (not perfect but fine in practice)
* solution to prevent user from launching the same LC again. See Bug 3548.
*
* Better solution is change
* org.eclipse.debug.internal.core.LaunchConfiguration.launch()
*
* but we don't want to modify platform code. .............03/18/07
*/
static private List<ILaunchConfiguration> m_beingLaunched = Collections
.synchronizedList(new LinkedList<ILaunchConfiguration>());
public boolean isBeingLaunched(ILaunchConfiguration lc) {
if (lc instanceof ILaunchConfigurationWorkingCopy)
lc = ((ILaunchConfigurationWorkingCopy) lc).getOriginal();
if (!m_beingLaunched.contains(lc))
return false;
else {
String cfgName = lc.getName();
String format = LaunchMessages.getString("NokiaAbstractLaunchDelegate.LaunchUnderway"); //$NON-NLS-1$
String msg = MessageFormat.format(format, new Object[] { cfgName });
showMessage(LaunchMessages.getString("CarbideCPPLaunchDelegate.DebuggerName"), msg); //$NON-NLS-1$
return true;
}
}
public void addBeingLaunched(ILaunchConfiguration lc) {
if (lc instanceof ILaunchConfigurationWorkingCopy)
lc = ((ILaunchConfigurationWorkingCopy) lc).getOriginal();
m_beingLaunched.add(lc);
}
public void removeBeingLaunched(ILaunchConfiguration lc) {
if (lc instanceof ILaunchConfigurationWorkingCopy)
lc = ((ILaunchConfigurationWorkingCopy) lc).getOriginal();
m_beingLaunched.remove(lc);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#buildForLaunch(org.eclipse.debug.core.ILaunchConfiguration,
* java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public boolean buildForLaunch(ILaunchConfiguration configuration,
String mode, IProgressMonitor monitor) throws CoreException {
/*
* This override is just for preventing user from launching the same LC
* twice. See my comment [comment_20070318] in this file.
*/
if (isBeingLaunched(configuration))
return false;
try {
addBeingLaunched(configuration);
return super.buildForLaunch(configuration, mode, monitor);
} finally {
removeBeingLaunched(configuration);
}
}
protected String getPluginID() {
return LaunchPlugin.getUniqueIdentifier();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ILaunchConfigurationDelegate2#preLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration,
* java.lang.String, org.eclipse.core.runtime.IProgressMonitor)
*/
public boolean preLaunchCheck(ILaunchConfiguration configuration,
String mode, IProgressMonitor monitor) throws CoreException {
// Prevent launching the same LC again. See my comment
// [comment_20070318] in this file.
if (isBeingLaunched(configuration))
return false;
try {
addBeingLaunched(configuration);
// Don't go on if a session (from another LC) is being started or
// stopped.
synchronized (Session.sessionStartStopMutex()) {
}
if (monitor.isCanceled())
return false;
// If a debug session is already running for the given launch
// configuration, don't allow user to start another session.
//
if (Session.preLaunchCheckForExistingTarget(configuration)) {
// Pop up a dialog telling user.
String cfgName = configuration.getName();
showMessage(LaunchMessages.getString("CarbideCPPLaunchDelegate.DebuggerName"), //$NON-NLS-1$
LaunchMessages.getString("CarbideCPPLaunchDelegate.DebugUnderway") + //$NON-NLS-1$
"\t\"" + cfgName + "\""); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
return super.preLaunchCheck(configuration, mode, monitor);
} finally {
removeBeingLaunched(configuration);
}
}
public static IProject getProject(ILaunchConfiguration configuration) {
String projectName = null;
try {
projectName = getProjectName(configuration);
} catch (CoreException e) {}
if (projectName != null) {
projectName = projectName.trim();
if (projectName.length() > 0) {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
return project;
}
}
return null;
}
protected void doAdditionalSessionSetup(Session session) {
if (session.getOSDataManager() == null)
session.setOSDataManager(new OSDataManager(session));
session.setExecutableTargetedCallback(new ExecutableTargeted());
}
protected ILaunchConfiguration synchronizeWithProjectAccessPaths(
ICProject project, ILaunchConfiguration config)
throws CoreException {
ILaunchConfigurationWorkingCopy workingCopy = config.getWorkingCopy();
addSourceMappingToLaunch(workingCopy);
return workingCopy.doSave();
}
/**
* Returns list of executables that need to be targeted for debugging other
* than the main executable which is always targeted. This list includes the
* binaries imported into the project as well as all the executables built
* as part of the inf file.
*
* @return
* @throws CModelException
*/
protected IPath[] getOtherExecutables(ICProject project, IPath exePath,
ILaunchConfiguration config, IProgressMonitor monitor) throws CModelException {
ArrayList<IPath> targetedBinaries = new ArrayList<IPath>();
ExecutablesManager.getExecutablesManager().setRefreshNeeded(true);
targetedBinaries.addAll(getBldInfExecutables(project, exePath, config, monitor));
return (IPath[]) targetedBinaries.toArray(new IPath[targetedBinaries
.size()]);
}
/**
* Returns list of executables that are built as part of the bld inf file.
* Excludes the exe specified in the launch configuration.
* @param monitor
*
* @return
*/
protected List<IPath> getBldInfExecutables(ICProject project,
IPath mainExePath, ILaunchConfiguration config, IProgressMonitor monitor) {
// Target imported executables in the project
ArrayList<IPath> infExecutables = new ArrayList<IPath>();
try {
String executablesToTarget = ExecutablesTab.getExecutablesToTarget(config, monitor);
if (executablesToTarget.length() > 0) {
StringTokenizer tokenizer = new StringTokenizer(executablesToTarget,
","); //$NON-NLS-1$
while (tokenizer.hasMoreTokens()) {
String exe = tokenizer.nextToken();
String enabled = tokenizer.nextToken();
Path exePath = new Path(exe);
if (enabled.compareTo("0") == 0 //$NON-NLS-1$
|| exePath.lastSegment().equalsIgnoreCase(
mainExePath.lastSegment())) {
continue;
}
infExecutables.add(exePath);
}
}
} catch (CoreException ce) {
return infExecutables;
}
return infExecutables;
}
/**
* Search binary files in the project for those that need be debugged (aside
* from the binary built by the project) for this debug session.
*
* @return
* @throws CModelException
*/
protected List<IPath> getImportedExecutables(ICProject project,
IPath exePath) throws CModelException {
// Target imported executables in the project
ArrayList<IPath> importedBinaries = new ArrayList<IPath>();
if (projectMayHaveImportedExecutables(project))
{
IBinary[] binaries = project.getBinaryContainer().getBinaries();
for (int i = 0; i < binaries.length; i++) {
IBinary binary = binaries[i];
// only look at binaries with the correct cpu type (e.g. "arm",
// "x86")
if (binary.getCPU().toLowerCase().contains(getCPUString())) {
IPath binaryPath = binary.getResource().getLocation();
/*
* Weed out other binaries that has the same base file name as
* the main target. That is pretty common when the project has
* build configs for different SDKs, say, S60_3 ARMV5, S60_3
* GCCE, UIQ21 GCC. E.g. a Blackflag project may contain several
* versions of "blackflag.exe" from different build configs.
* Targeting all those would cause problems in DE, say, when
* setting a breakpoint during debug, DE would try to duplicate
* the break in all other "blackflag.exe", resulting various
* problems. ..... 08/30/06
*/
if (binaryPath.lastSegment().equals(exePath.lastSegment()))
continue;
if (!binary.getPath().lastSegment().startsWith(".") && !binaryPath.equals(exePath)) { //$NON-NLS-1$
importedBinaries.add(binaryPath);
}
}
}
}
return importedBinaries;
}
private boolean projectMayHaveImportedExecutables(ICProject project) {
try {
IResource[] members = project.getProject().members();
for (int i = 0; i < members.length; i++) {
if (members[i].isLinked())
return true;
}
} catch (CoreException e) {}
return false;
}
// Move to CDT when the import wizard is integrated. There is another copy
// of this function in the import wizard code.
private void waitForParsingToComplete() {
// After adding the binary parsers to the project we have to wait for
// them to finish
// before we can extract a good list of source files.
String binaryTaskName = ""; //$NON-NLS-1$
IJobManager jobMan = Job.getJobManager();
Job[] jobs = jobMan.find(null);
for (int i = 0; i < jobs.length; i++) {
if (jobs[i].getName().equals(binaryTaskName)) {
try {
jobs[i].join();
} catch (InterruptedException e) {
}
}
}
}
private void addSourceMappingToDirector(AbstractSourceLookupDirector director, ILaunchConfiguration configuration) throws CoreException {
ArrayList containerList = new ArrayList(Arrays.asList(director.getSourceContainers()));
boolean hasSymbianContainer = false;
SymbianSourceContainer symbianContainer = null;
for (Iterator iter = containerList.iterator(); iter.hasNext() && !hasSymbianContainer;) {
ISourceContainer container = (ISourceContainer) iter.next();
if (container instanceof SymbianSourceContainer)
{
hasSymbianContainer = true;
}
}
if (!hasSymbianContainer) {
String epocRootPath = configuration.getAttribute( SymbianPlugin.Epoc_Root, (String)null );
if (epocRootPath != null)
{
symbianContainer = new SymbianSourceContainer(new Path(epocRootPath));
symbianContainer.init(director);
containerList.add(symbianContainer);
}
}
director.setSourceContainers((ISourceContainer[]) containerList.toArray(new ISourceContainer[containerList.size()]));
}
private void addSourceMappingToLaunch(ILaunchConfigurationWorkingCopy configuration) throws CoreException {
String memento = null;
String type = null;
memento = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String) null);
type = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String) null);
if (type == null) {
type = configuration.getType().getSourceLocatorId();
}
ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
ISourceLocator locator = launchManager.newSourceLocator(type);
if (locator instanceof AbstractSourceLookupDirector) {
AbstractSourceLookupDirector director = (AbstractSourceLookupDirector) locator;
if (memento == null) {
director.initializeDefaults(configuration);
} else {
director.initializeFromMemento(memento, configuration);
}
addSourceMappingToDirector(director, configuration);
configuration.setAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, director.getMemento());
configuration.setAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, director.getId());
}
}
protected String getTargetLabel(String processName) {
String format = "{0} (Launched {1})"; //$NON-NLS-1$
String timestamp = DateFormat.getInstance().format(new Date(System.currentTimeMillis()));
return MessageFormat.format(format, new Object[]{processName, timestamp});
}
protected String getCPUString() {
// default. May be overridden.
return "arm"; //$NON-NLS-1$
}
protected void showMessage(final String title, final String msg) {
// Pop up a dialog telling user.
Display display = Display.getCurrent();
if (display == null) {
display = Display.getDefault();
}
display.syncExec(new Runnable() {
public void run() {
MessageDialog.openWarning(CUIPlugin.getActiveWorkbenchShell(),
title, msg);
}
});
}
@Override
protected boolean existsErrors(IProject proj) throws CoreException {
return CarbideCPPBuilder.projectHasBuildErrors(proj);
}
}