blob: 9afaf35c1f2b9c5fc05fe3f295fa11298aab76b3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 The Regents of the University of California.
* This material was produced under U.S. Government contract W-7405-ENG-36
* for Los Alamos National Laboratory, which is operated by the University
* of California for the U.S. Department of Energy. The U.S. Government has
* rights to use, reproduce, and distribute this software. NEITHER THE
* GOVERNMENT NOR THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR
* ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified
* to produce derivative works, such modified software should be clearly marked,
* so as not to confuse it with the version available from LANL.
*
* Additionally, 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
*
* LA-CC 04-115
*******************************************************************************/
package org.eclipse.ptp.internal.debug.sdm.core;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ptp.core.IPTPLaunchConfigurationConstants;
import org.eclipse.ptp.core.Preferences;
import org.eclipse.ptp.core.jobs.IJobStatus;
import org.eclipse.ptp.core.jobs.IPJobStatus;
import org.eclipse.ptp.core.jobs.JobManager;
import org.eclipse.ptp.debug.core.IPDebugger;
import org.eclipse.ptp.debug.core.launch.IPLaunch;
import org.eclipse.ptp.debug.core.pdi.IPDIDebugger;
import org.eclipse.ptp.debug.core.pdi.IPDISession;
import org.eclipse.ptp.debug.core.pdi.PDIException;
import org.eclipse.ptp.debug.core.pdi.event.IPDIEventFactory;
import org.eclipse.ptp.debug.core.pdi.manager.IPDIManagerFactory;
import org.eclipse.ptp.debug.core.pdi.model.IPDIModelFactory;
import org.eclipse.ptp.debug.core.pdi.request.IPDIRequestFactory;
import org.eclipse.ptp.internal.debug.core.pdi.Session;
import org.eclipse.ptp.internal.debug.sdm.core.messages.Messages;
import org.eclipse.ptp.internal.debug.sdm.core.pdi.PDIDebugger;
import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteFileService;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import org.eclipse.remote.core.launch.IRemoteLaunchConfigService;
import org.osgi.framework.Bundle;
/**
* Main SDM debugger specified using the parallelDebugger extension point.
*
* A new instance of this class is created for each debug session.
*
* @author clement
*
*/
public class SDMDebugger implements IPDebugger {
private static final String WORKING_DIR = ".eclipsesettings"; //$NON-NLS-1$
private static final String SDM = "sdm"; //$NON-NLS-1$
private static final String BUNDLE_PREFIX = "org.eclipse.ptp."; //$NON-NLS-1$
private static final String OS = "os"; //$NON-NLS-1$
private final IPDIDebugger fPdiDebugger = new PDIDebugger();
private final IPDIModelFactory fModelFactory = new SDMModelFactory();
private final IPDIManagerFactory fManagerFactory = new SDMManagerFactory();
private final IPDIEventFactory fEventFactory = new SDMEventFactory();
private final IPDIRequestFactory fRequestFactory = new SDMRequestFactory();
/*
* (non-Javadoc)
*
* @see org.eclipse.ptp.debug.core.IPDebugger#cleanup(org.eclipse.ptp.debug.core .launch.IPLaunch)
*/
public synchronized void cleanup(IPLaunch launch) {
// Nothing to do
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ptp.debug.core.IPDebugger#createDebugSession(long, org.eclipse.ptp.debug.core.launch.IPLaunch,
* org.eclipse.core.runtime.IPath)
*/
/**
* @since 5.0
*/
public synchronized IPDISession createDebugSession(long timeout, final IPLaunch launch, IProgressMonitor monitor)
throws CoreException {
int jobSize = getJobSize(launch);
IPDISession session;
try {
session = new Session(fManagerFactory, fRequestFactory, fEventFactory, fModelFactory, launch.getLaunchConfiguration(),
timeout, fPdiDebugger, launch.getJobId(), jobSize);
} catch (PDIException e) {
throw newCoreException(e.getLocalizedMessage());
}
return session;
}
private String deploySDM(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, 100);
boolean useBuiltin = configuration.getAttribute(SDMLaunchConfigurationConstants.ATTR_DEBUGGER_USE_BUILTIN_SDM, false);
if (useBuiltin) {
IRemoteLaunchConfigService launchService = SDMDebugCorePlugin.getService(IRemoteLaunchConfigService.class);
IRemoteConnection remoteConnection = launchService.getActiveConnection(configuration);
if (remoteConnection != null) {
if (!remoteConnection.isOpen()) {
try {
progress.subTask(Messages.SDMDebugger_Opening_connection);
remoteConnection.open(progress.newChild(10));
} catch (RemoteConnectionException e) {
throw new CoreException(new Status(IStatus.ERROR, SDMDebugCorePlugin.getUniqueIdentifier(),
Messages.SDMDebugger_Could_not_open_connection, e));
}
}
if (remoteConnection.isOpen()) {
String osName = normalize(remoteConnection.getProperty(IRemoteConnection.OS_NAME_PROPERTY));
String osArch = remoteConnection.getProperty(IRemoteConnection.OS_ARCH_PROPERTY);
if (osName != null && osArch != null) {
Bundle bundle = Platform.getBundle(BUNDLE_PREFIX + osName);
if (bundle != null) {
IRemoteFileService fileService = remoteConnection.getService(IRemoteFileService.class);
if (fileService != null) {
/*
* Create the .eclipssettings directory if it doesn't exist on the remote machine. The mkdir
* does nothing if the directory already exists.
*/
IPath destDirPath = new Path(fileService.getBaseDirectory()).append(WORKING_DIR);
IFileStore destDir = fileService.getResource(destDirPath.toString());
destDir.mkdir(EFS.NONE, progress.newChild(1));
/*
* Find sdm in correct bundle
*/
IFileStore local = null;
IPath srcPath = new Path(OS).append(osName).append(osArch).append(SDM);
URL jarURL = FileLocator.find(bundle, srcPath, null);
if (jarURL != null) {
try {
jarURL = FileLocator.toFileURL(jarURL);
local = EFS.getStore(URIUtil.toURI(jarURL));
} catch (Exception e) {
throw new CoreException(new Status(IStatus.ERROR, SDMDebugCorePlugin.getUniqueIdentifier(),
Messages.SDMDebugger_Could_not_locate_SDM_exectuable, e));
}
}
/*
* Now copy the sdm if necessary
*/
if (local != null) {
IFileStore destPath = destDir.getChild(SDM);
IFileInfo destInfo = destPath.fetchInfo(EFS.NONE, progress.newChild(10));
IFileInfo localInfo = local.fetchInfo(EFS.NONE, progress.newChild(10));
/*
* Only copy if the sdm does not exist, or the size is different from the local version
* TODO: checking the size is not very accurate, it would be better to use a crypto hash
*/
if (!destInfo.exists() || destInfo.getLength() != localInfo.getLength()) {
progress.subTask(Messages.SDMDebugger_Copying_SDM_to_target_system);
local.copy(destPath, EFS.OVERWRITE, progress.newChild(70));
}
/*
* Check if the sdm is executable. Make it executable if not.
*/
destInfo = destPath.fetchInfo(EFS.NONE, progress.newChild(10));
destInfo.setAttribute(EFS.ATTRIBUTE_EXECUTABLE, true);
/*
* Make sure sdm is not writeable to world
*/
destInfo.setAttribute(EFS.ATTRIBUTE_OTHER_WRITE, false);
destPath.putInfo(destInfo, EFS.SET_ATTRIBUTES, progress.newChild(10));
return destPath.toURI().getPath();
}
}
}
}
}
}
}
return configuration.getAttribute(SDMLaunchConfigurationConstants.ATTR_DEBUGGER_SDM_EXECUTABLE, ""); //$NON-NLS-1$
}
/**
* Work out the expected number of processes in the job. If it hasn't been specified, assume one.
*
* @param launch
* job that was launched
* @return number of processes
*/
private int getJobSize(IPLaunch launch) {
int nprocs = 1;
IJobStatus job = JobManager.getInstance().getJob(launch.getJobControl().getControlId(), launch.getJobId());
if (job != null) {
IPJobStatus pJob = (IPJobStatus) job.getAdapter(IPJobStatus.class);
if (pJob != null) {
nprocs = pJob.getNumberOfProcesses();
if (nprocs == 0) {
nprocs = 1;
}
}
}
return nprocs;
}
/**
* Helper method to locate the remote connection used by the launch configuration
*
* @param configuration
* launch configuration
* @return remote connection or null if none specified
* @throws CoreException
*/
private IRemoteConnection getRemoteConnection(ILaunchConfiguration configuration, IProgressMonitor monitor)
throws CoreException {
IRemoteLaunchConfigService launchConfigService = SDMDebugCorePlugin.getService(IRemoteLaunchConfigService.class);
return launchConfigService.getActiveConnection(configuration);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ptp.debug.core.IPDebugger#initialize(org.eclipse.debug.core .ILaunchConfiguration,
* org.eclipse.core.runtime.IProgressMonitor)
*/
/**
* @since 5.0
*/
public synchronized void initialize(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
SubMonitor progress = SubMonitor.convert(monitor, 30);
ILaunchConfigurationWorkingCopy workingCopy = configuration.getWorkingCopy();
List<String> dbgArgs = new ArrayList<String>();
try {
fPdiDebugger.initialize(configuration, dbgArgs, progress.newChild(10));
} catch (PDIException e) {
throw newCoreException(e.getLocalizedMessage());
}
String localAddress = configuration.getAttribute(IPTPLaunchConfigurationConstants.ATTR_DEBUGGER_HOST, "localhost"); //$NON-NLS-1$
dbgArgs.add("--host=" + localAddress); //$NON-NLS-1$
String debuggerBackend = configuration.getAttribute(SDMLaunchConfigurationConstants.ATTR_DEBUGGER_SDM_BACKEND,
(String) null);
if (debuggerBackend != null) {
dbgArgs.add("--debugger=" + debuggerBackend); //$NON-NLS-1$
}
String dbgPath = configuration.getAttribute(SDMLaunchConfigurationConstants.ATTR_DEBUGGER_SDM_BACKEND_PATH, (String) null);
if (dbgPath != null) {
dbgArgs.add("--debugger_path=" + dbgPath); //$NON-NLS-1$
}
if (Preferences.getBoolean(SDMDebugCorePlugin.getUniqueIdentifier(), SDMPreferenceConstants.SDM_DEBUG_ENABLED)) {
dbgArgs.add("--debug=" + Preferences.getInt(SDMDebugCorePlugin.getUniqueIdentifier(), SDMPreferenceConstants.SDM_DEBUG_LEVEL)); //$NON-NLS-1$
}
String dbgExePath = deploySDM(configuration, progress.newChild(10));
verifyResource(dbgExePath, configuration, progress.newChild(10));
workingCopy.setAttribute(IPTPLaunchConfigurationConstants.ATTR_DEBUGGER_ARGS, stringify(dbgArgs));
workingCopy.setAttribute(IPTPLaunchConfigurationConstants.ATTR_DEBUGGER_EXECUTABLE_PATH, dbgExePath);
workingCopy.doSave();
}
/**
* Create a CoreException that can be thrown
*
* @param exception
* @return CoreException
*/
private CoreException newCoreException(String message) {
Status status = new Status(IStatus.ERROR, SDMDebugCorePlugin.getUniqueIdentifier(), message, null);
return new CoreException(status);
}
private String normalize(String osName) {
return osName.toLowerCase().replaceAll("\\s", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Create a string containing each element of the list separated by a space
*
* @param list
* @return
*/
private String stringify(List<String> list) {
String result = ""; //$NON-NLS-1$
for (int i = 0; i < list.size(); i++) {
if (i > 0) {
result += " "; //$NON-NLS-1$
}
result += list.get(i);
}
return result;
}
/**
* Verify that the resource "path" actually exists. This just checks that the path references something real.
*
* @param path
* path to verify
* @param configuration
* launch configuration
* @return IPath representing the path
* @throws CoreException
* is thrown if the verification fails or the user cancels the progress monitor
* @since 5.0
*/
private IPath verifyResource(String path, ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
IRemoteConnection conn = getRemoteConnection(configuration, monitor);
if (monitor.isCanceled()) {
throw newCoreException(Messages.SDMDebugger_Operation_canceled_by_user);
}
if (conn == null) {
throw new CoreException(new Status(IStatus.ERROR, SDMDebugCorePlugin.PLUGIN_ID, Messages.SDMDebugger_2));
}
IRemoteFileService fileService = conn.getService(IRemoteFileService.class);
if (fileService == null) {
throw new CoreException(new Status(IStatus.ERROR, SDMDebugCorePlugin.PLUGIN_ID, Messages.SDMDebugger_3));
}
if (!fileService.getResource(path).fetchInfo().exists()) {
throw new CoreException(new Status(IStatus.ERROR, SDMDebugCorePlugin.PLUGIN_ID, NLS.bind(Messages.SDMDebugger_5,
new Object[] { path })));
}
return new Path(path);
}
}