diff options
Diffstat (limited to 'valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org')
12 files changed, 1254 insertions, 0 deletions
diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/Messages.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/Messages.java new file mode 100644 index 0000000000..1bbba28640 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/Messages.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.linuxtools.internal.valgrind.launch.remote.messages"; //$NON-NLS-1$ + public static String ValgrindRemoteLaunchDelegate_error_launch_failed; + public static String ValgrindRemoteLaunchDelegate_error_no_fs; + public static String ValgrindRemoteLaunchDelegate_error_no_peers; + public static String ValgrindRemoteLaunchDelegate_error_no_proc; + public static String ValgrindRemoteLaunchDelegate_error_no_streams; + public static String ValgrindRemoteLaunchDelegate_task_name; + public static String ValgrindRemoteProcess_error_proc_not_term; + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchConstants.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchConstants.java new file mode 100644 index 0000000000..ce0cdd35b2 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchConstants.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +public final class RemoteLaunchConstants { + + private static final String PLUGIN_ID = "org.eclipse.linuxtools.valgrind.launch.remote"; //$NON-NLS-1$ + + public static final String ATTR_REMOTE_OUTPUTDIR = PLUGIN_ID + ".REMOTE_OUTPUTDIR"; //$NON-NLS-1$ + + public static final String DEFAULT_REMOTE_OUTPUTDIR = "/tmp"; //$NON-NLS-1$ +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchPlugin.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchPlugin.java new file mode 100644 index 0000000000..7258376dd0 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchPlugin.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class RemoteLaunchPlugin extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.linuxtools.valgrind.launch.remote"; //$NON-NLS-1$ + + // The shared instance + private static RemoteLaunchPlugin plugin; + + /** + * The constructor + */ + public RemoteLaunchPlugin() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static RemoteLaunchPlugin getDefault() { + return plugin; + } + +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchStep.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchStep.java new file mode 100644 index 0000000000..cb0b162017 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/RemoteLaunchStep.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import java.util.LinkedList; + +import org.eclipse.tm.tcf.protocol.IChannel; + + +public abstract class RemoteLaunchStep { + + private LinkedList<RemoteLaunchStep> steps; + private IChannel channel; + + public RemoteLaunchStep(LinkedList<RemoteLaunchStep> steps, IChannel channel) { + this.steps = steps; + this.channel = channel; + steps.add(this); + } + + public abstract void start() throws Exception; + + public void done() { + if (channel.getState() != IChannel.STATE_OPEN) { + return; + } + try { + if (!steps.isEmpty()) { + steps.removeFirst().start(); + } + } + catch (Throwable x) { + channel.terminate(x); + } + } + +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteCommand.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteCommand.java new file mode 100644 index 0000000000..bd846d5944 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteCommand.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import org.eclipse.linuxtools.internal.valgrind.core.ValgrindCommand; +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IProcesses; +import org.eclipse.tm.tcf.services.IProcesses.ProcessContext; +import org.eclipse.tm.tcf.services.IProcesses.ProcessesListener; +import org.eclipse.tm.tcf.services.IStreams; + +public class ValgrindRemoteCommand extends ValgrindCommand { + private IChannel channel; + private Map<String, String> streamIds; + private LinkedList<RemoteLaunchStep> launchSteps; + + public ValgrindRemoteCommand(IChannel channel, LinkedList<RemoteLaunchStep> launchSteps) { + this.channel = channel; + this.launchSteps = launchSteps; + streamIds = new HashMap<String, String>(); + } + + @Override + protected Process startProcess(final String[] commandArray, final Object env, + final File workDir, final String binPath, boolean usePty) throws IOException { + final IStreams streamsService = channel.getRemoteService(IStreams.class); + final IProcesses procService = channel.getRemoteService(IProcesses.class); + + // Connect streams + final IStreams.StreamsListener streamsListener = new IStreams.StreamsListener() { + + public void disposed(String stream_type, String stream_id) { + } + + public void created(String stream_type, String stream_id, String context_id) { + streamIds.put(stream_id, context_id); + } + }; + + new RemoteLaunchStep(launchSteps, channel) { + + @Override + public void start() throws Exception { + // Register streams as they are created + streamsService.subscribe(IProcesses.NAME, streamsListener, new IStreams.DoneSubscribe() { + + public void doneSubscribe(IToken token, Exception error) { + if (error != null) { + channel.terminate(error); + } + else { + done(); + } + } + }); + } + }; + + new RemoteLaunchStep(launchSteps, channel) { + + @SuppressWarnings("unchecked") + @Override + public void start() throws Exception { + // Create process + procService.start(workDir.getAbsolutePath(), binPath, commandArray, (Map<String, String>) env, false, new IProcesses.DoneStart() { + public void doneStart(IToken token, Exception error, + final ProcessContext context) { + if (error != null) { + channel.terminate(error); + } + else { + final ValgrindRemoteProcess remoteProcess = new ValgrindRemoteProcess(context, channel, launchSteps); + process = remoteProcess; + + // Register as a listener to retrieve exit code + ProcessesListener listener = new ProcessesListener() { + public void exited(String process_id, int exit_code) { + if (process_id.equals(context.getID())) { + remoteProcess.setExitCode(exit_code); + remoteProcess.setTerminated(true); + + done(); + } + } + }; + procService.addListener(listener); + final String stdinID = (String) context.getProperties().get(IProcesses.PROP_STDIN_ID); + final String stdoutID = (String) context.getProperties().get(IProcesses.PROP_STDOUT_ID); + final String stderrID = (String) context.getProperties().get(IProcesses.PROP_STDERR_ID); + for (final String id : streamIds.keySet().toArray(new String[streamIds.size()])) { + if (id.equals(stdinID)) { + remoteProcess.connectOutputStream(stdinID); + } + else if (id.equals(stdoutID)) { + remoteProcess.connectInputStream(stdoutID); + } + else if (id.equals(stderrID)) { + remoteProcess.connectErrorStream(stderrID); + } + else { + disconnectStream(id); + } + } + } + } + }); + } + }; + + return process; + } + + private void disconnectStream(String id) { + streamIds.remove(id); + if (channel.getState() != IChannel.STATE_OPEN) { + return; + } + + IStreams streams = channel.getRemoteService(IStreams.class); + streams.disconnect(id, new IStreams.DoneDisconnect() { + public void doneDisconnect(IToken token, Exception error) { + if (channel.getState() != IChannel.STATE_OPEN) { + return; + } + if (error != null) { + channel.terminate(error); + } + } + }); + } + +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchDelegate.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchDelegate.java new file mode 100644 index 0000000000..db2e489b9d --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchDelegate.java @@ -0,0 +1,593 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +import org.eclipse.cdt.debug.core.CDebugUtils; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.SubMonitor; +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.model.IProcess; +import org.eclipse.linuxtools.internal.valgrind.launch.ValgrindLaunchConfigurationDelegate; +import org.eclipse.linuxtools.internal.valgrind.launch.ValgrindLaunchPlugin; +import org.eclipse.linuxtools.internal.valgrind.ui.ValgrindUIPlugin; +import org.eclipse.linuxtools.valgrind.core.IValgrindMessage; +import org.eclipse.linuxtools.valgrind.launch.IValgrindOutputDirectoryProvider; +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IPeer; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.protocol.Protocol; +import org.eclipse.tm.tcf.services.IFileSystem; +import org.eclipse.tm.tcf.services.IFileSystem.DirEntry; +import org.eclipse.tm.tcf.services.IFileSystem.DoneMkDir; +import org.eclipse.tm.tcf.services.IFileSystem.FileAttrs; +import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException; +import org.eclipse.tm.tcf.services.IFileSystem.IFileHandle; +import org.eclipse.tm.tcf.services.IProcesses; +import org.eclipse.tm.tcf.services.IStreams; + +public class ValgrindRemoteLaunchDelegate extends +ValgrindLaunchConfigurationDelegate { + + private IChannel channel; + private SubMonitor monitor; + private IFileSystem fsService; + private IProcesses procService; + private LinkedList<RemoteLaunchStep> launchSteps; + private Throwable ex; + private IPath localOutputDir; + + public void launch(final ILaunchConfiguration config, String mode, + final ILaunch launch, IProgressMonitor m) throws CoreException { + if (m == null) { + m = new NullProgressMonitor(); + } + launchSteps = new LinkedList<RemoteLaunchStep>(); + + monitor = SubMonitor + .convert( + m, + Messages.ValgrindRemoteLaunchDelegate_task_name, 10); + // check for cancellation + if (monitor.isCanceled()) { + return; + } + + this.config = config; + this.launch = launch; + try { + // remove any output from previous run + ValgrindUIPlugin.getDefault().resetView(); + // reset stored launch data + getPlugin().setCurrentLaunchConfiguration(null); + getPlugin().setCurrentLaunch(null); + + // FIXME find Valgrind binary if not already done + final IPath valgrindLocation = getPlugin().getValgrindLocation(); + // also ensure Valgrind version is usable + getPlugin().getValgrindVersion(); + + monitor.worked(1); + + // Open TCF Channel + Map<String, IPeer> peers = Protocol.getLocator().getPeers(); + // XXX Use 127.0.0.1 to test + IPeer peer = null; + for (String id : peers.keySet()) { + if (id.contains("127.0.0.1")) { + peer = peers.get(id); + } + } + if (peer == null) { + abort(Messages.ValgrindRemoteLaunchDelegate_error_no_peers, null, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); + } + else { + channel = peer.openChannel(); + channel.addChannelListener(new IChannel.IChannelListener() { + + public void onChannelOpened() { + try { + IStreams streamService = channel.getRemoteService(IStreams.class); + if (streamService == null) { + abort(Messages.ValgrindRemoteLaunchDelegate_error_no_streams, null, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); + } + + fsService = channel.getRemoteService(IFileSystem.class); + if (fsService == null) { + abort(Messages.ValgrindRemoteLaunchDelegate_error_no_fs, null, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); + } + + procService = channel.getRemoteService(IProcesses.class); + if (procService == null) { + abort(Messages.ValgrindRemoteLaunchDelegate_error_no_proc, null, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); + } + + command = new ValgrindRemoteCommand(channel, launchSteps); + + // Copy binary using FileSystem service + final IPath exePath = CDebugUtils.verifyProgramPath(config); + final IPath remoteDir = Path.fromOSString("/tmp"); + final IPath remoteFile = remoteDir.append(exePath.lastSegment()); + final IPath remoteLogDir = Path.fromOSString("/tmp").append("eclipse-valgrind-" + System.currentTimeMillis()); + + try { + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + writeFileToRemote(exePath, remoteFile, this); + } + }; + + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + fsService.mkdir(remoteLogDir.toOSString(), new FileAttrs(0, 0, 0, 0, 0, 0, 0, null), new DoneMkDir() { + public void doneMkDir(IToken token, + FileSystemException error) { + if (error != null) { + disconnect(error); + } + else { + done(); + } + } + }); + } + }; + + + String[] arguments = getProgramArgumentsArray(config); + + // Start process using Processes service + startRemoteProcess(config, launch, + valgrindLocation, remoteFile, + arguments, remoteDir.toFile(), remoteLogDir); + + // Copy log files from remote + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + fsService.opendir(outputPath.toOSString(), new IFileSystem.DoneOpen() { + + public void doneOpen(IToken token, FileSystemException error, + IFileHandle handle) { + if (error != null) { + disconnect(error); + } + + readDir(handle); + } + + private void readDir(final IFileHandle handle) { + fsService.readdir(handle, new IFileSystem.DoneReadDir() { + + public void doneReadDir(IToken token, FileSystemException error, + DirEntry[] entries, boolean eof) { + if (error != null) { + disconnect(error); + } + else { + for (DirEntry entry : entries) { + final IPath remotePath = outputPath.append(entry.filename); + final IPath localPath = localOutputDir.append(entry.filename); + + // Copy each log file + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + writeFileToLocal(remotePath, localPath, this); + } + }; + + // Delete log file on remote + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + fsService.remove(remotePath.toOSString(), new IFileSystem.DoneRemove() { + public void doneRemove(IToken token, FileSystemException error) { + if (error != null) { + disconnect(error); + } + else { + done(); + } + } + }); + } + }; + } + + if (!eof) { + readDir(handle); + } + else { + // Close the log directory + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + fsService.close(handle, new IFileSystem.DoneClose() { + public void doneClose(IToken token, FileSystemException error) { + if (error != null) { + disconnect(error); + } + else { + done(); + } + } + }); + } + }; + + // Delete the remote log directory + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + fsService.rmdir(outputPath.toOSString(), new IFileSystem.DoneRemove() { + public void doneRemove(IToken token, FileSystemException error) { + if (error != null) { + disconnect(error); + } + else { + done(); + } + } + }); + } + }; + + // Close the channel + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + disconnect(null); + done(); + } + }; + + done(); + } + } + } + }); + } + }); + } + }; + + // Begin executing launch steps + launchSteps.removeFirst().start(); + } catch (Throwable e) { + disconnect(e); + } + } catch (CoreException e) { + disconnect(e); + } + } + + public void onChannelClosed(Throwable error) { + channel.removeChannelListener(this); + if (error != null) { + ex = error; + } + } + + public void congestionLevel(int level) { + } + }); + } + + // Wait for TCF connection to close + while (channel.getState() != IChannel.STATE_CLOSED) { + Thread.sleep(100); + } + + if (ex != null) { + abort(Messages.ValgrindRemoteLaunchDelegate_error_launch_failed, ex, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); + } + + // store these for use by other classes + getPlugin().setCurrentLaunchConfiguration(config); + getPlugin().setCurrentLaunch(launch); + + // parse Valgrind logs + IValgrindMessage[] messages = parseLogs(localOutputDir); + + // create launch summary string to distinguish this launch + launchStr = createLaunchStr(); + + // create view + ValgrindUIPlugin.getDefault().createView(launchStr, toolID); + // set log messages + ValgrindUIPlugin.getDefault().getView().setMessages(messages); + monitor.worked(1); + + // pass off control to extender + dynamicDelegate.handleLaunch(config, launch, localOutputDir, monitor.newChild(3)); + + // refresh view + ValgrindUIPlugin.getDefault().refreshView(); + + // show view + ValgrindUIPlugin.getDefault().showView(); + monitor.worked(1); + } catch (IOException e) { + abort("Error starting process", e, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR); //$NON-NLS-1$ + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + m.done(); + } + } + + protected String createLaunchStr() { + return config.getName() + + " [" + getPlugin().getToolName(toolID) + "] " + process.getLabel(); //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + protected String getPluginID() { + return ValgrindLaunchPlugin.PLUGIN_ID; + } + + private void disconnect(Throwable t) { + if (fsService != null) { + // TODO Cleanup log output and binary + } + channel.terminate(t); + } + + private void writeFileToRemote(IPath localFile, IPath remoteFile, final RemoteLaunchStep step) throws CoreException, FileNotFoundException { + final InputStream inp = new FileInputStream(localFile.toOSString()); + int flags = IFileSystem.TCF_O_WRITE | IFileSystem.TCF_O_CREAT | IFileSystem.TCF_O_TRUNC; + fsService.open(remoteFile.toOSString(), flags, new FileAttrs(IFileSystem.ATTR_PERMISSIONS, 0, 0, 0, + IFileSystem.S_IRUSR | IFileSystem.S_IWUSR | IFileSystem.S_IXUSR, 0, 0, null), new IFileSystem.DoneOpen() { + + IFileHandle handle; + long offset = 0; + final Set<IToken> cmds = new HashSet<IToken>(); + final byte[] buf = new byte[0x1000]; + + public void doneOpen(IToken token, FileSystemException error, IFileHandle handle) { + this.handle = handle; + if (error != null) { + disconnect(error); + } + else { + writeNext(); + } + } + + private void writeNext() { + try { + while (cmds.size() < 8) { + int rd = inp.read(buf); + if (rd < 0) { + close(); + break; + } + cmds.add(fsService.write(handle, offset, buf, 0, rd, new IFileSystem.DoneWrite() { + + public void doneWrite(IToken token, FileSystemException error) { + cmds.remove(token); + if (error != null) { + disconnect(error); + } + else { + writeNext(); + } + } + })); + offset += rd; + } + } + catch (Throwable x) { + disconnect(x); + } + } + + private void close() { + if (cmds.size() > 0) { + return; + } + try { + inp.close(); + fsService.close(handle, new IFileSystem.DoneClose() { + + public void doneClose(IToken token, FileSystemException error) { + if (error != null) { + disconnect(error); + } + else { + step.done(); + } + } + }); + } + catch (Throwable x) { + disconnect(x); + } + } + }); + } + + private void writeFileToLocal(IPath remoteFile, IPath localFile, final RemoteLaunchStep step) throws CoreException, FileNotFoundException { + final OutputStream out = new FileOutputStream(localFile.toOSString()); + int flags = IFileSystem.TCF_O_READ; + fsService.open(remoteFile.toOSString(), flags, null, new IFileSystem.DoneOpen() { + + IFileHandle handle; + long offset = 0; + Set<IToken> cmds = new HashSet<IToken>(); + static final int BUF_LENGTH = 0x1000; + + public void doneOpen(IToken token, FileSystemException error, IFileHandle handle) { + this.handle = handle; + if (error != null) { + disconnect(error); + } + else { + readNext(); + } + } + + private void readNext() { + try { + cmds.add(fsService.read(handle, offset, BUF_LENGTH, new IFileSystem.DoneRead() { + + public void doneRead(IToken token, FileSystemException error, byte[] data, + boolean eof) { + cmds.remove(token); + if (error != null) { + disconnect(error); + } + else { + try { + out.write(data); + offset += data.length; + if (eof) { + close(); + } + else { + readNext(); + } + } catch (IOException e) { + disconnect(e); + } + } + } + })); + } + catch (Throwable x) { + disconnect(x); + } + } + + private void close() { + if (cmds.size() > 0) { + return; + } + try { + out.close(); + fsService.close(handle, new IFileSystem.DoneClose() { + + public void doneClose(IToken token, FileSystemException error) { + if (error != null) { + disconnect(error); + } + else { + step.done(); + } + } + }); + } + catch (Throwable x) { + disconnect(x); + } + } + }); + } + + private void startRemoteProcess(final ILaunchConfiguration config, + final ILaunch launch, final IPath valgrindLocation, + final IPath exePath, final String[] arguments, final File workDir, IPath logDir) + throws Exception { + // set output directory in config + setOutputPath(config, logDir); + outputPath = verifyOutputPath(config); + + // create/empty local output directory + IValgrindOutputDirectoryProvider provider = getPlugin().getOutputDirectoryProvider(); + localOutputDir = provider.getOutputPath(); + createDirectory(localOutputDir); + + // tool that was launched + toolID = getTool(config); + // ask tool extension for arguments + dynamicDelegate = getDynamicDelegate(toolID); + String[] opts = getValgrindArgumentsArray(config); + + // set the default source locator if required + setDefaultSourceLocator(launch, config); + + ArrayList<String> cmdLine = new ArrayList<String>( + 1 + arguments.length); + cmdLine.add(valgrindLocation.toOSString()); + cmdLine.addAll(Arrays.asList(opts)); + cmdLine.add(exePath.toOSString()); + cmdLine.addAll(Arrays.asList(arguments)); + final String[] commandArray = (String[]) cmdLine + .toArray(new String[cmdLine.size()]); + boolean usePty = config.getAttribute( + ICDTLaunchConfigurationConstants.ATTR_USE_TERMINAL, + ICDTLaunchConfigurationConstants.USE_TERMINAL_DEFAULT); + monitor.worked(1); + + // TODO Get remote environment + @SuppressWarnings("unchecked") + Map<String, String> env = (Map<String, String>) config.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, (Map<String, String>) null); + + // check for cancellation + if (monitor.isCanceled()) { + disconnect(null); + } + // call Valgrind + command.execute(commandArray, env, workDir, valgrindLocation.toOSString(), usePty); + + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + monitor.worked(3); + process = createNewProcess(launch, command.getProcess(), + commandArray[0]); + // set the command line used + process.setAttribute(IProcess.ATTR_CMDLINE, + command.getCommandLine()); + done(); + } + }; + } + + @Override + protected void setOutputPath(ILaunchConfiguration config, IPath outputPath) + throws CoreException, IOException { + ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy(); + wc.setAttribute(RemoteLaunchConstants.ATTR_REMOTE_OUTPUTDIR, outputPath.toPortableString()); + wc.doSave(); + } + + @Override + protected IPath verifyOutputPath(ILaunchConfiguration config) + throws CoreException { + return Path.fromOSString(config.getAttribute(RemoteLaunchConstants.ATTR_REMOTE_OUTPUTDIR, RemoteLaunchConstants.DEFAULT_REMOTE_OUTPUTDIR)); + } +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchShortcut.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchShortcut.java new file mode 100644 index 0000000000..3363033d74 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchShortcut.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import org.eclipse.linuxtools.internal.valgrind.launch.ValgrindLaunchShortcut; + +public class ValgrindRemoteLaunchShortcut extends ValgrindLaunchShortcut { + +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchTabGroup.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchTabGroup.java new file mode 100644 index 0000000000..5fcb342289 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteLaunchTabGroup.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.linuxtools.internal.profiling.launch.remote.ProfileRemoteLaunchConfigurationTabGroup; +import org.eclipse.linuxtools.internal.valgrind.launch.ValgrindOptionsTab; + +public class ValgrindRemoteLaunchTabGroup extends + ProfileRemoteLaunchConfigurationTabGroup { + + @Override + public AbstractLaunchConfigurationTab[] getProfileTabs() { + return new AbstractLaunchConfigurationTab[] { new ValgrindOptionsTab() }; + } + +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteProcess.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteProcess.java new file mode 100644 index 0000000000..60c4ab7fb6 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindRemoteProcess.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.LinkedList; + +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IProcesses; +import org.eclipse.tm.tcf.services.IProcesses.DoneCommand; + +public class ValgrindRemoteProcess extends Process { + private IProcesses.ProcessContext context; + private IChannel channel; + private LinkedList<RemoteLaunchStep> launchSteps; + private Boolean terminated; + private Integer exitCode; + private OutputStream outputStream; + private InputStream inputStream; + private InputStream errorStream; + + public ValgrindRemoteProcess(IProcesses.ProcessContext context, IChannel channel, LinkedList<RemoteLaunchStep> launchSteps) { + this.context = context; + this.channel = channel; + this.launchSteps = launchSteps; + terminated = false; + } + + @Override + public OutputStream getOutputStream() { + return outputStream; + } + + @Override + public InputStream getInputStream() { + return inputStream; + } + + @Override + public InputStream getErrorStream() { + return errorStream; + } + + @Override + public int waitFor() throws InterruptedException { + while (!getTerminated()) { + Thread.sleep(100); + } + return exitCode; + } + + @Override + public int exitValue() { + if (exitCode == null) { + throw new IllegalThreadStateException(Messages.ValgrindRemoteProcess_error_proc_not_term); + } + return exitCode; + } + + @Override + public void destroy() { + context.terminate(new DoneCommand() { + public void doneCommand(IToken token, Exception error) { + } + }); + } + + public void setTerminated(boolean terminated) { + synchronized (this.terminated) { + this.terminated = terminated; + } + } + + public Boolean getTerminated() { + synchronized (terminated) { + return terminated; + } + } + + public void setExitCode(Integer exitCode) { + this.exitCode = exitCode; + } + + public void connectOutputStream(String id) { + outputStream = new ValgrindTCFOutputStream(channel, id, launchSteps); + } + + public void connectInputStream(String id) { + inputStream = new ValgrindTCFInputStream(channel, id, launchSteps); + } + + public void connectErrorStream(String id) { + errorStream = new ValgrindTCFInputStream(channel, id, launchSteps); + } + +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindTCFInputStream.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindTCFInputStream.java new file mode 100644 index 0000000000..c45747d4f8 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindTCFInputStream.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedList; + +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IStreams; +import org.eclipse.tm.tcf.services.IStreams.DoneRead; + +public class ValgrindTCFInputStream extends InputStream { + private LinkedList<RemoteLaunchStep> launchSteps; + private IChannel channel; + private IStreams streamsService; + private String streamId; + private boolean done; + private byte[] buf; + private Exception ex; + + public ValgrindTCFInputStream(IChannel channel, String streamId, LinkedList<RemoteLaunchStep> launchSteps) { + this.channel = channel; + this.streamId = streamId; + this.launchSteps = launchSteps; + streamsService = channel.getRemoteService(IStreams.class); + } + + @Override + public int read() throws IOException { + read1(1); + + return buf[0]; + } + + private void read1(final int size) throws IOException { + done = false; + ex = null; + buf = null; + + new RemoteLaunchStep(launchSteps, channel) { + @Override + public void start() throws Exception { + streamsService.read(streamId, size, new DoneRead() { + + public void doneRead(IToken token, Exception error, int lost_size, + byte[] data, boolean eos) { + if (error != null) { + ex = error; + } + else { + buf = data; + } + done = true; + done(); + } + }); + } + }; + + try { + while (!done) { + Thread.sleep(100); + } + } catch (InterruptedException e) { + } + + if (ex != null) { + throw new IOException(ex); + } + } + + @Override + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + + read1(len); + + // Did we read less than requested? + if (buf.length < len) { + len = buf.length; + } + + System.arraycopy(buf, 0, b, off, len); + return len; + } +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindTCFOutputStream.java b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindTCFOutputStream.java new file mode 100644 index 0000000000..75fc35f845 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/ValgrindTCFOutputStream.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2010 Elliott Baron + * 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: + * Elliott Baron <ebaron@fedoraproject.org> - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.internal.valgrind.launch.remote; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.LinkedList; + +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IStreams; +import org.eclipse.tm.tcf.services.IStreams.DoneWrite; + +public class ValgrindTCFOutputStream extends OutputStream { + private IChannel channel; + private LinkedList<RemoteLaunchStep> launchSteps; + private IStreams streamsService; + private String streamId; + private boolean done; + private Exception ex; + + public ValgrindTCFOutputStream(IChannel channel, String streamId, LinkedList<RemoteLaunchStep> launchSteps) { + this.channel = channel; + this.streamId = streamId; + this.launchSteps = launchSteps; + streamsService = channel.getRemoteService(IStreams.class); + } + + + @Override + public void write(int b) throws IOException { + write1(new byte[] { (byte) b }, 0, 1); + } + + + private void write1(final byte[] b, final int off, final int len) throws IOException { + done = false; + ex = null; + + new RemoteLaunchStep(launchSteps, channel) { + + @Override + public void start() throws Exception { + streamsService.write(streamId, b, off, len, new DoneWrite() { + + public void doneWrite(IToken token, Exception error) { + if (error != null) { + ex = null; + } + else { + done(); + } + } + }); + } + }; + + try { + while (!done) { + Thread.sleep(100); + } + } catch (InterruptedException e) { + } + + if (ex != null) { + throw new IOException(ex); + } + } + + @Override + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if ((off < 0) || (off > b.length) || (len < 0) + || ((off + len) > b.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + + write1(b, off, len); + } +} diff --git a/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/messages.properties b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/messages.properties new file mode 100644 index 0000000000..98fa0e75e1 --- /dev/null +++ b/valgrind/org.eclipse.linuxtools.valgrind.launch.remote/src/org/eclipse/linuxtools/internal/valgrind/launch/remote/messages.properties @@ -0,0 +1,7 @@ +ValgrindRemoteLaunchDelegate_error_launch_failed=Launch failed. +ValgrindRemoteLaunchDelegate_error_no_fs=FileSystem service is unavailable on target. +ValgrindRemoteLaunchDelegate_error_no_peers=No peers available. +ValgrindRemoteLaunchDelegate_error_no_proc=Processes service is unavailable on target. +ValgrindRemoteLaunchDelegate_error_no_streams=Streams service is unavailable on target. +ValgrindRemoteLaunchDelegate_task_name=Profiling Remote C/C++ Application +ValgrindRemoteProcess_error_proc_not_term=Process has not terminated. |