diff options
author | Darin Wright | 2007-10-09 21:03:43 +0000 |
---|---|---|
committer | Darin Wright | 2007-10-09 21:03:43 +0000 |
commit | 07f1e796ae8a43d56d3010bd3e85063b318a0ad3 (patch) | |
tree | 35f7610d1674c644f814f9a8b8bb8a858feffd39 /org.eclipse.debug.examples.core/src/org | |
parent | 50371b66ac350e9f64991048058ad251a191c90d (diff) | |
download | eclipse.platform.debug-07f1e796ae8a43d56d3010bd3e85063b318a0ad3.tar.gz eclipse.platform.debug-07f1e796ae8a43d56d3010bd3e85063b318a0ad3.tar.xz eclipse.platform.debug-07f1e796ae8a43d56d3010bd3e85063b318a0ad3.zip |
release of original PDA code base
Diffstat (limited to 'org.eclipse.debug.examples.core/src/org')
19 files changed, 2723 insertions, 0 deletions
diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/DebugCorePlugin.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/DebugCorePlugin.java new file mode 100644 index 000000000..f58fe8613 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/DebugCorePlugin.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.osgi.framework.BundleContext; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.*; + +/** + * The main plugin class to be used in the desktop. + */ +public class DebugCorePlugin extends Plugin { + //The shared instance. + private static DebugCorePlugin plugin; + //Resource bundle. + private ResourceBundle resourceBundle; + + /** + * Unique identifier for the PDA debug model (value + * <code>pda.debugModel</code>). + */ + public static final String ID_PDA_DEBUG_MODEL = "pda.debugModel"; + + /** + * Name of the string substitution variable that resolves to the + * location of a local Perl executable (value <code>perlExecutable</code>). + */ + public static final String VARIALBE_PERL_EXECUTABLE = "perlExecutable"; + /** + * Launch configuration attribute key. Value is a path to a perl + * program. The path is a string representing a full path + * to a perl program in the workspace. + */ + public static final String ATTR_PDA_PROGRAM = ID_PDA_DEBUG_MODEL + ".ATTR_PDA_PROGRAM"; + + /** + * Identifier for the PDA launch configuration type + * (value <code>pda.launchType</code>) + */ + public static final String ID_PDA_LAUNCH_CONFIGURATION_TYPE = "pda.launchType"; + + /** + * The constructor. + */ + public DebugCorePlugin() { + super(); + plugin = this; + } + + /** + * This method is called upon plug-in activation + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /** + * This method is called when the plug-in is stopped + */ + public void stop(BundleContext context) throws Exception { + super.stop(context); + plugin = null; + resourceBundle = null; + } + + /** + * Returns the shared instance. + */ + public static DebugCorePlugin getDefault() { + return plugin; + } + + /** + * Returns the string from the plugin's resource bundle, + * or 'key' if not found. + */ + public static String getResourceString(String key) { + ResourceBundle bundle = DebugCorePlugin.getDefault().getResourceBundle(); + try { + return (bundle != null) ? bundle.getString(key) : key; + } catch (MissingResourceException e) { + return key; + } + } + + /** + * Returns the plugin's resource bundle, + */ + public ResourceBundle getResourceBundle() { + try { + if (resourceBundle == null) + resourceBundle = ResourceBundle.getBundle("org.eclipse.debug.examples.core.pda.DebugCorePluginResources"); + } catch (MissingResourceException x) { + resourceBundle = null; + } + return resourceBundle; + } + + /** + * Return a <code>java.io.File</code> object that corresponds to the specified + * <code>IPath</code> in the plugin directory, or <code>null</code> if none. + */ + public static File getFileInPlugin(IPath path) { + try { + URL installURL = + new URL(getDefault().getDescriptor().getInstallURL(), path.toString()); + URL localURL = Platform.asLocalURL(installURL); + return new File(localURL.getFile()); + } catch (IOException ioe) { + return null; + } + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDALineBreakpoint.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDALineBreakpoint.java new file mode 100644 index 000000000..24062b0b5 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDALineBreakpoint.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.breakpoints; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.LineBreakpoint; +import org.eclipse.debug.examples.core.pda.DebugCorePlugin; +import org.eclipse.debug.examples.core.pda.model.IPDAEventListener; +import org.eclipse.debug.examples.core.pda.model.PDADebugTarget; +import org.eclipse.debug.examples.core.pda.model.PDAThread; + + +/** + * PDA line breakpoint + */ +public class PDALineBreakpoint extends LineBreakpoint implements IPDAEventListener { + + // target currently installed in + private PDADebugTarget fTarget; + + /** + * Default constructor is required for the breakpoint manager + * to re-create persisted breakpoints. After instantiating a breakpoint, + * the <code>setMarker(...)</code> method is called to restore + * this breakpoint's attributes. + */ + public PDALineBreakpoint() { + } + + /** + * Constructs a line breakpoint on the given resource at the given + * line number. The line number is 1-based (i.e. the first line of a + * file is line number 1). The PDA VM uses 0-based line numbers, + * so this line number translation is done at breakpoint install time. + * + * @param resource file on which to set the breakpoint + * @param lineNumber 1-based line number of the breakpoint + * @throws CoreException if unable to create the breakpoint + */ + public PDALineBreakpoint(final IResource resource, final int lineNumber) throws CoreException { + IWorkspaceRunnable runnable = new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + IMarker marker = resource.createMarker("org.eclipse.debug.examples.core.pda.markerType.lineBreakpoint"); + setMarker(marker); + marker.setAttribute(IBreakpoint.ENABLED, Boolean.TRUE); + marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); + marker.setAttribute(IBreakpoint.ID, getModelIdentifier()); + marker.setAttribute(IMarker.MESSAGE, "Line Breakpoint: " + resource.getName() + " [line: " + lineNumber + "]"); + } + }; + run(getMarkerRule(resource), runnable); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IBreakpoint#getModelIdentifier() + */ + public String getModelIdentifier() { + return DebugCorePlugin.ID_PDA_DEBUG_MODEL; + } + + /** + * Returns whether this breakpoint is a run-to-line breakpoint + * + * @return whether this breakpoint is a run-to-line breakpoint + */ + public boolean isRunToLineBreakpoint() { + return false; + } + + /** + * Installs this breakpoint in the given interprettor. + * Registeres this breakpoint as an event listener in the + * given target and creates the breakpoint specific request. + * + * @param target PDA interprettor + * @throws CoreException if installation fails + */ + public void install(PDADebugTarget target) throws CoreException { + fTarget = target; + target.addEventListener(this); + createRequest(target); + } + + /** + * Create the breakpoint specific request in the target. Subclasses + * should override. + * + * @param target PDA interprettor + * @throws CoreException if request creation fails + */ + protected void createRequest(PDADebugTarget target) throws CoreException { + //#ifdef ex3 +//# // TODO: Exercise 3 - create breakpoint request in interpreter + //#else + target.sendRequest("set " + (getLineNumber() - 1)); + //#endif + } + + /** + * Removes this breakpoint's event request from the target. Subclasses + * should override. + * + * @param target PDA interprettor + * @throws CoreException if clearing the request fails + */ + protected void clearRequest(PDADebugTarget target) throws CoreException { + //#ifdef ex3 +//# // TODO: Exercise 3 - clear breakpoint request in interpreter + //#else + target.sendRequest("clear " + (getLineNumber() - 1)); + //#endif + } + + /** + * Removes this breakpoint from the given interprettor. + * Removes this breakpoint as an event listener and clears + * the request for the interprettor. + * + * @param target PDA interprettor + * @throws CoreException if removal fails + */ + public void remove(PDADebugTarget target) throws CoreException { + target.removeEventListener(this); + clearRequest(target); + fTarget = null; + + } + + /** + * Returns the target this breakpoint is installed in or <code>null</code>. + * + * @return the target this breakpoint is installed in or <code>null</code> + */ + protected PDADebugTarget getDebugTarget() { + return fTarget; + } + + /** + * Notify's the PDA interprettor that this breakpoint has been hit. + */ + protected void notifyThread() { + if (fTarget != null) { + try { + IThread[] threads = fTarget.getThreads(); + if (threads.length == 1) { + PDAThread thread = (PDAThread)threads[0]; + thread.suspendedBy(this); + } + } catch (DebugException e) { + } + } + } + + /* (non-Javadoc) + * + * Subclasses should override to handle their breakpoint specific event. + * + * @see org.eclipse.debug.examples.core.pda.model.IPDAEventListener#handleEvent(java.lang.String) + */ + public void handleEvent(String event) { + if (event.startsWith("suspended breakpoint")) { + handleHit(event); + } + } + + /** + * Determines if this breakpoint was hit and notifies the thread. + * + * @param event breakpoint event + */ + private void handleHit(String event) { + int lastSpace = event.lastIndexOf(' '); + if (lastSpace > 0) { + String line = event.substring(lastSpace + 1); + int lineNumber = Integer.parseInt(line); + // breakpoints event line numbers are 0 based, model objects are 1 based + lineNumber++; + try { + if (getLineNumber() == lineNumber) { + notifyThread(); + } + } catch (CoreException e) { + } + } + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDARunToLineBreakpoint.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDARunToLineBreakpoint.java new file mode 100644 index 000000000..b861fff20 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDARunToLineBreakpoint.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.breakpoints; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IBreakpoint; + +/** + * A run to line breakpoint. + */ +public class PDARunToLineBreakpoint extends PDALineBreakpoint { + + private IFile fSourceFile; + + /** + * Constructs a run-to-line breakpoint in the given PDA program. + * + * @param resource PDA source file + * @param lineNumber line to run to + * @exception DebugException if unable to create the breakpoint + */ + public PDARunToLineBreakpoint(final IFile resource, final int lineNumber) throws DebugException { + IWorkspaceRunnable runnable = new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + // associate with workspace root to avoid drawing in editor ruler + IMarker marker = ResourcesPlugin.getWorkspace().getRoot().createMarker("org.eclipse.debug.examples.core.pda.markerType.lineBreakpoint"); + setMarker(marker); + marker.setAttribute(IBreakpoint.ENABLED, Boolean.TRUE); + marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); + marker.setAttribute(IBreakpoint.ID, getModelIdentifier()); + setRegistered(false); + fSourceFile = resource; + } + }; + run(getMarkerRule(resource), runnable); + } + + /** + * Returns whether this breakpoint is a run-to-line breakpoint + * + * @return whether this breakpoint is a run-to-line breakpoint + */ + public boolean isRunToLineBreakpoint() { + return true; + } + + /** + * Returns the source file this breakpoint is contained in. + * + * @return the source file this breakpoint is contained in + */ + public IFile getSourceFile() { + return fSourceFile; + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDAWatchpoint.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDAWatchpoint.java new file mode 100644 index 000000000..ab819d0b5 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/breakpoints/PDAWatchpoint.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.breakpoints; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IWatchpoint; +import org.eclipse.debug.examples.core.pda.model.PDADebugTarget; + + +/** + * A watchpoint. + */ +public class PDAWatchpoint extends PDALineBreakpoint implements IWatchpoint { + + // 'read' or 'write' depending on what caused the last suspend for this watchpoint + private String fLastSuspendType; + + // marker attributes + public static final String ACCESS = "ACCESS"; + public static final String MODIFICATION = "MODIFICATION"; + public static final String FUNCTION_NAME = "FUNCTION_NAME"; + public static final String VAR_NAME = "VAR_NAME"; + + /** + * Default constructor is required for the breakpoint manager + * to re-create persisted breakpoints. After instantiating a breakpoint, + * the <code>setMarker(...)</code> method is called to restore + * this breakpoint's attributes. + */ + public PDAWatchpoint() { + } + /** + * Constructs a line breakpoint on the given resource at the given + * line number. The line number is 1-based (i.e. the first line of a + * file is line number 1). The PDA VM uses 0-based line numbers, + * so this line number translation is done at breakpoint install time. + * + * @param resource file on which to set the breakpoint + * @param lineNumber 1-based line number of the breakpoint + * @param functionName function name the variable is defined in + * @param varName variable name that watchpoint is set on + * @param access whether this is an access watchpoint + * @param modification whether this in a modification watchpoint + * @throws CoreException if unable to create the watchpoint + */ + public PDAWatchpoint(final IResource resource, final int lineNumber, final String functionName, final String varName, final boolean access, final boolean modification) throws CoreException { + IWorkspaceRunnable runnable = new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + IMarker marker = resource.createMarker("org.eclipse.debug.examples.core.pda.markerType.watchpoint"); + setMarker(marker); + setEnabled(true); + ensureMarker().setAttribute(IMarker.LINE_NUMBER, lineNumber); + ensureMarker().setAttribute(IBreakpoint.ID, getModelIdentifier()); + setAccess(access); + setModification(modification); + setVariable(functionName, varName); + marker.setAttribute(IMarker.MESSAGE, "Watchpoint: " + resource.getName() + " [line: " + lineNumber + "]"); + } + }; + run(getMarkerRule(resource), runnable); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IWatchpoint#isAccess() + */ + public boolean isAccess() throws CoreException { + return getMarker().getAttribute(ACCESS, true); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IWatchpoint#setAccess(boolean) + */ + public void setAccess(boolean access) throws CoreException { + setAttribute(ACCESS, access); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IWatchpoint#isModification() + */ + public boolean isModification() throws CoreException { + return getMarker().getAttribute(MODIFICATION, true); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IWatchpoint#setModification(boolean) + */ + public void setModification(boolean modification) throws CoreException { + setAttribute(MODIFICATION, modification); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IWatchpoint#supportsAccess() + */ + public boolean supportsAccess() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IWatchpoint#supportsModification() + */ + public boolean supportsModification() { + return true; + } + + /** + * Sets the variable and function names the watchpoint is set on. + * + * @param functionName function name + * @param variableName variable name + * @throws CoreException if an exception occurrs setting marker attribtues + */ + protected void setVariable(String functionName, String variableName) throws CoreException { + setAttribute(VAR_NAME, variableName); + setAttribute(FUNCTION_NAME, functionName); + } + + /** + * Returns the name of the variable this watchpoint is set on. + * + * @return the name of the variable this watchpoint is set on + * @throws CoreException if unable to access the attribute + */ + public String getVariableName() throws CoreException { + return getMarker().getAttribute(VAR_NAME, (String)null); + } + + /** + * Returns the name of the function the variable associted with this watchpoint is defined in. + * + * @return the name of the function the variable associted with this watchpoint is defined in + * @throws CoreException if unable to access the attribute + */ + public String getFunctionName() throws CoreException { + return getMarker().getAttribute(FUNCTION_NAME, (String)null); + } + + /** + * Sets the type of event that causes the last suspend event. + * + * @param description one of 'read' or 'write' + */ + public void setSuspendType(String description) { + fLastSuspendType = description; + } + + /** + * Returns the type of event that caused the last suspend. + * + * @return 'read', 'write', or <code>null</code> if undefined + */ + public String getSuspendType() { + return fLastSuspendType; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.examples.core.pda.breakpoints.PDALineBreakpoint#createRequest(org.eclipse.debug.examples.core.pda.model.PDADebugTarget) + */ + protected void createRequest(PDADebugTarget target) throws CoreException { + int flag = 0; + if (isAccess()) { + flag = flag | 1; + } + if (isModification()) { + flag = flag | 2; + } + target.sendRequest("watch " + getFunctionName() + "::" + getVariableName() + " " + flag); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.examples.core.pda.breakpoints.PDALineBreakpoint#clearRequest(org.eclipse.debug.examples.core.pda.model.PDADebugTarget) + */ + protected void clearRequest(PDADebugTarget target) throws CoreException { + target.sendRequest("watch " + getFunctionName() + "::" + getVariableName() + " " + 0); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.examples.core.pda.model.IPDAEventListener#handleEvent(java.lang.String) + */ + public void handleEvent(String event) { + if (event.startsWith("suspended watch")) { + handleHit(event); + } + } + + /** + * Determines if this breakpoint was hit and notifies the thread. + * + * @param event breakpoint event + */ + private void handleHit(String event) { + String[] strings = event.split(" "); + if (strings.length == 4) { + String fv = strings[3]; + int j = fv.indexOf("::"); + if (j > 0) { + String fcn = fv.substring(0, j); + String var = fv.substring(j + 2); + try { + if (getVariableName().equals(var) && getFunctionName().equals(fcn)) { + setSuspendType(strings[2]); + notifyThread(); + } + } catch (CoreException e) { + } + } + } + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/launcher/PDALaunchDelegate.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/launcher/PDALaunchDelegate.java new file mode 100644 index 000000000..e78fc56b6 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/launcher/PDALaunchDelegate.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.launcher; + +import java.io.File; +import java.io.IOException; +import java.net.ServerSocket; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.variables.IValueVariable; +import org.eclipse.core.variables.VariablesPlugin; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.LaunchConfigurationDelegate; +import org.eclipse.debug.examples.core.pda.DebugCorePlugin; +import org.eclipse.debug.examples.core.pda.model.PDADebugTarget; + + +/** + * Launches PDA program on a PDA interpretter written in Perl + */ +public class PDALaunchDelegate extends LaunchConfigurationDelegate { + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ILaunchConfigurationDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor) + */ + public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException { + //#ifdef ex1 +//# // TODO: Exercise 1 - Launch a command shell as a system process to echo "foo" + //#elseif ex1_answer +//# Process process = DebugPlugin.exec(new String[]{"cmd", "/C", "\"echo foo\""}, null); +//# new RuntimeProcess(launch, process, "Hello", null); + //#else + + List commandList = new ArrayList(); + + // Perl executable + IValueVariable perl = VariablesPlugin.getDefault().getStringVariableManager().getValueVariable(DebugCorePlugin.VARIALBE_PERL_EXECUTABLE); + if (perl == null) { + abort("Perl executable location undefined. Check value of ${perlExecutable}.", null); + } + String path = perl.getValue(); + if (path == null) { + abort("Perl executable location unspecified. Check value of ${perlExecutable}.", null); + } + File exe = new File(path); + if (!exe.exists()) { + abort(MessageFormat.format("Specified Perl executable {0} does not exist. Check value of $perlExecutable.", new String[]{path}), null); + } + commandList.add(path); + + // Add PDA VM + File vm = DebugCorePlugin.getFileInPlugin(new Path("pdavm/pda.pl")); + if (vm == null) { + abort("Missing PDA VM", null); + } + commandList.add(vm.getAbsolutePath()); + + // program name + String program = configuration.getAttribute(DebugCorePlugin.ATTR_PDA_PROGRAM, (String)null); + if (program == null) { + abort("Perl program unspecified.", null); + } + + IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(program)); + if (!file.exists()) { + abort(MessageFormat.format("Perl program {0} does not exist.", new String[] {file.getFullPath().toString()}), null); + } + + commandList.add(file.getLocation().toOSString()); + + // if in debug mode, add debug arguments - i.e. '-debug requestPort eventPort' + int requestPort = -1; + int eventPort = -1; + if (mode.equals(ILaunchManager.DEBUG_MODE)) { + requestPort = findFreePort(); + eventPort = findFreePort(); + if (requestPort == -1 || eventPort == -1) { + abort("Unable to find free port", null); + } + commandList.add("-debug"); + commandList.add("" + requestPort); + commandList.add("" + eventPort); + } + + String[] commandLine = (String[]) commandList.toArray(new String[commandList.size()]); + Process process = DebugPlugin.exec(commandLine, null); + IProcess p = DebugPlugin.newProcess(launch, process, path); + // if in debug mode, create a debug target + if (mode.equals(ILaunchManager.DEBUG_MODE)) { + IDebugTarget target = new PDADebugTarget(launch, p, requestPort, eventPort); + launch.addDebugTarget(target); + } + //#endif + } + + /** + * Throws an exception with a new status containing the given + * message and optional exception. + * + * @param message error message + * @param e underlying exception + * @throws CoreException + */ + private void abort(String message, Throwable e) throws CoreException { + throw new CoreException(new Status(IStatus.ERROR, DebugCorePlugin.getDefault().getDescriptor().getUniqueIdentifier(), 0, message, e)); + } + + /** + * Returns a free port number on localhost, or -1 if unable to find a free port. + * + * @return a free port number on localhost, or -1 if unable to find a free port + */ + public static int findFreePort() { + ServerSocket socket= null; + try { + socket= new ServerSocket(0); + return socket.getLocalPort(); + } catch (IOException e) { + } finally { + if (socket != null) { + try { + socket.close(); + } catch (IOException e) { + } + } + } + return -1; + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/IPDAEventListener.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/IPDAEventListener.java new file mode 100644 index 000000000..6935ad32b --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/IPDAEventListener.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +/** + * Listeners are notified of events occurring in a PDA program + * being interpreted. + * <p> + * The events generated by the interpreter are: + * <ul> + * <li><code>started</code> - the interpreter has started (guaranteed to be the + * first event sent)</li> + * <li><code>terminated</code> - the interpreter has terminated (guaranteed to be + * the last event sent)</li> + * <li><code>suspended X</code> - the interpreter has suspended and entered debug mode; + * <code>X</code> is the cause of the suspension: + * <ul> + * <li><code>breakpoint N</code> - a breakpoint at line <code>N</code> was hit</li> + * <li><code>client</code> - a client request to suspend has completed</li> + * <li><code>drop</code> - a client request to drop a frame has completed</li> + * <li><code>event E</code> - an error was encountered, where <code>E</code> is one + * of <code>unimpinstr</code> or <code>nosuchlabel</code></li> + * <li><code>step</code> - a step request has completed</li> + * <li><code>watch A F::V</code> - a watchpoint was hit for reason <code>A</code> + * (<code>read</code> or <code>write</code>), on variable <code>V</code> in + * function <code>F</code></li> + * </ul> + * </li> + * <li><code>resumed X</code> - the interpreter has resumed execution in run mode; + * <code>X</code> is the cause of the resume: + * <ul> + * <li><code>step</code> - a step request has been initiated</li> + * <li><code>client</code> - a client request to resume has been initiated</li> + * </ul> + * </li> + * <li><code>unimplemented instruction X</code> - an unimplemented instruction <code>X</code> + * was encountered</li> + * <li><code>no such label X</code> - a branch or call to an unknown label <code>X</code> + * was encountered</li> + * </ul> + * </p> + */ +public interface IPDAEventListener { + + /** + * Notification the given event occurred in the target program + * being interpreted. + * + * @param event the event + */ + public void handleEvent(String event); + +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAArray.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAArray.java new file mode 100644 index 000000000..e27e1bad1 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAArray.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; + +public class PDAArray extends PDAValue { + + /** + * An array splits a value into its words + * + * @param value existing value + * @throws DebugException + */ + public PDAArray(PDAValue value) throws DebugException { + super(value.getPDADebugTarget(), value.getValueString()); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValue#hasVariables() + */ + public boolean hasVariables() throws DebugException { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValue#getVariables() + */ + public IVariable[] getVariables() throws DebugException { + String string = getValueString(); + String[] words = string.split("\\W+"); + IVariable[] variables = new IVariable[words.length]; + for (int i = 0; i < words.length; i++) { + String word = words[i]; + variables[i] = new PDAArrayEntry(getPDADebugTarget(), i, new PDAValue(getPDADebugTarget(), word)); + } + return variables; + } + +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAArrayEntry.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAArrayEntry.java new file mode 100644 index 000000000..9ff3ca74e --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAArrayEntry.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.IVariable; + +public class PDAArrayEntry extends PDADebugElement implements IVariable { + + private IValue fValue; + private int fIndex; + + /** + * Constructs a new array entry + * + * @param target debug target + * @param index index in the array + * @param value value of the entry + */ + public PDAArrayEntry(IDebugTarget target, int index, IValue value) { + super(target); + fValue = value; + fIndex = index; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IVariable#getValue() + */ + public IValue getValue() throws DebugException { + return fValue; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IVariable#getName() + */ + public String getName() throws DebugException { + return "[" + fIndex + "]"; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IVariable#getReferenceTypeName() + */ + public String getReferenceTypeName() throws DebugException { + return "String"; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IVariable#hasValueChanged() + */ + public boolean hasValueChanged() throws DebugException { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#setValue(java.lang.String) + */ + public void setValue(String expression) throws DebugException { + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#setValue(org.eclipse.debug.core.model.IValue) + */ + public void setValue(IValue value) throws DebugException { + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#supportsValueModification() + */ + public boolean supportsValueModification() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#verifyValue(java.lang.String) + */ + public boolean verifyValue(String expression) throws DebugException { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#verifyValue(org.eclipse.debug.core.model.IValue) + */ + public boolean verifyValue(IValue value) throws DebugException { + return false; + } + +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDADebugElement.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDADebugElement.java new file mode 100644 index 000000000..e64f22050 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDADebugElement.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.model.DebugElement; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.examples.core.pda.DebugCorePlugin; + + +/** + * Common function for PDA debug elements. + */ +public class PDADebugElement extends DebugElement { + + /** + * Constructs a new debug element in the given target. + * + * @param target debug target + */ + public PDADebugElement(IDebugTarget target) { + super(target); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier() + */ + public String getModelIdentifier() { + return DebugCorePlugin.ID_PDA_DEBUG_MODEL; + } + + /** + * Sends a request to the PDA interpreter, waits for and returns the reply. + * <p> + * Interpreter commands and replies are as follows: + * <ul> + * <li><code>clear N</code> - clear the breakpoint on line <code>N</code>; + * reply is <code>ok</code></li> + * <li><code>data</code> - return the contents of the data stack; reply is the data + * from oldest to newest as a single string <code>"value|value|value|...|value|"</code></li> + * <li><code>drop</code> - pops the top stack frame off the call stack setting the + * instruction pointer to the calling statement in the calling frame</li> + * <li><code>eventstop E B</code> - optionally stop the interpreter when an error event + * <code>E</code> is encountered; <code>B</code> specifies stop (<code>1</code>) or + * continue (<code>0</code>). The possible events are <code>unimpinstr</code> and + * <code>nosuchlabel</code>. Reply is <code>ok</code>. When an event is encountered, + * the interpreter sends the error event (for example <code>unimlpemented instruction foo</code>) + * and corresponding suspend event (for example <code>suspended event unimpinstr</code>).</li> + * <li><code>exit</code> - end the interpreter; reply is <code>ok</code></li> + * <li><code>popdata</code> - pop the top value off the data stack; reply is the value</li> + * <li><code>pushdata V</code> - push the value <code>V</code> onto the data stack; reply is + * <code>ok</code></li> + * <li><code>resume</code> - resume execution of the program; reply is <code>ok</code></li> + * <li><code>set N</code> - set a line breakpoint on line <code>N</code> (lines are indexed + * from 0); reply is <code>ok</code></li> + * <li><code>setdata N V</code> - set the contents of data stack element <code>N</code> to + * value <code>V</code> (the data stack is indexed from 0, 0 being the oldest); reply + * is <code>ok</code></li> + * <li><code>setvar N M V</code> - set the contents of variable <code>M</code> from the control + * stack <code>N</code> to value <code>V</code> (the control stack is indexed from 0, + * 0 being the oldest); reply is <code>ok</code></li> + * <li><code>stack</code> - return the contents of the control stack (program counters, function and + * variable names); reply is control stack from oldest to newest as a single string + * <code>frame#frame#frame...#frame</code> where each frame is a string + * <code>"filename|pc|function name|variable name|variable name|...|variable name"</code></li> + * <li><code>step</code> - single step forward; reply is <code>ok</code></li> + * <li><code>stepreturn</code> - single step forward until the next <code>return</code> op code; + * stop before executing the <code>return</code> ; reply is <code>ok</code></li> + * <li><code>suspend</code> - suspend execution of the program and listen for debug commands; + * reply is <code>ok</code></li> + * <li><code>watch F::V M</code> - set a watchpoint on variable <code>V</code> in function + * <code>F</code> to magic value <code>M</code>; the magic value is a bit flag corresponding + * to read access (1), write access (2), or both (3); the magic value 0 clears the watchpoint; + * reply is <code>ok</code></li> + * <li><code>var N M</code> - return the contents of variable <code>M</code> in the control + * stack frame <code>N</code> (stack frames are indexed from 0, 0 being the oldest); + * reply is variable value</li> + * </ul> + * </p> + * + * @param request command + * @return reply + * @throws DebugException if the request fails + */ + public String sendRequest(String request) throws DebugException { + return getPDADebugTarget().sendRequest(request); + } + + /** + * Returns the debug target as a PDA target. + * + * @return PDA debug target + */ + protected PDADebugTarget getPDADebugTarget() { + return (PDADebugTarget) getDebugTarget(); + } + + /** + * Returns the breakpoint manager + * + * @return the breakpoint manager + */ + protected IBreakpointManager getBreakpointManager() { + return DebugPlugin.getDefault().getBreakpointManager(); + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDADebugTarget.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDADebugTarget.java new file mode 100644 index 000000000..6df9fad76 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDADebugTarget.java @@ -0,0 +1,525 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.Vector; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.resources.IResource; +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.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.IBreakpointManagerListener; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.examples.core.pda.DebugCorePlugin; +import org.eclipse.debug.examples.core.pda.breakpoints.PDALineBreakpoint; +import org.eclipse.debug.examples.core.pda.breakpoints.PDARunToLineBreakpoint; + + +/** + * PDA Debug Target + */ +public class PDADebugTarget extends PDADebugElement implements IDebugTarget, IBreakpointManagerListener, IPDAEventListener { + + // associated system process (VM) + private IProcess fProcess; + + // containing launch object + private ILaunch fLaunch; + + // sockets to communicate with VM + private Socket fRequestSocket; + private PrintWriter fRequestWriter; + private BufferedReader fRequestReader; + private Socket fEventSocket; + private BufferedReader fEventReader; + + // terminated state + private boolean fTerminated = false; + + // threads + private IThread[] fThreads; + private PDAThread fThread; + + // event dispatch job + private EventDispatchJob fEventDispatch; + // event listeners + private Vector fEventListeners = new Vector(); + + /** + * Listens to events from the PDA VM and fires corresponding + * debug events. + */ + class EventDispatchJob extends Job { + + public EventDispatchJob() { + super("PDA Event Dispatch"); + setSystem(true); + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + protected IStatus run(IProgressMonitor monitor) { + String event = ""; + while (!isTerminated() && event != null) { + try { + event = fEventReader.readLine(); + if (event != null) { + Object[] listeners = fEventListeners.toArray(); + for (int i = 0; i < listeners.length; i++) { + ((IPDAEventListener)listeners[i]).handleEvent(event); + } + } + } catch (IOException e) { + terminated(); + } + } + return Status.OK_STATUS; + } + + } + + /** + * Registers the given event listener. The listener will be notified of + * events in the program being interpretted. Has no effect if the listener + * is already registered. + * + * @param listener event listener + */ + public void addEventListener(IPDAEventListener listener) { + if (!fEventListeners.contains(listener)) { + fEventListeners.add(listener); + } + } + + /** + * Deregisters the given event listener. Has no effect if the listener is + * not currently registered. + * + * @param listener event listener + */ + public void removeEventListener(IPDAEventListener listener) { + fEventListeners.remove(listener); + } + + /** + * Constructs a new debug target in the given launch for the + * associated PDA VM process. + * + * @param launch containing launch + * @param process PDA VM + * @param requestPort port to send requests to the VM + * @param eventPort port to read events from + * @exception CoreException if unable to connect to host + */ + public PDADebugTarget(ILaunch launch, IProcess process, int requestPort, int eventPort) throws CoreException { + super(null); + fLaunch = launch; + fProcess = process; + addEventListener(this); + try { + // give interpreter a chance to start + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + fRequestSocket = new Socket("localhost", requestPort); + fRequestWriter = new PrintWriter(fRequestSocket.getOutputStream()); + fRequestReader = new BufferedReader(new InputStreamReader(fRequestSocket.getInputStream())); + // give interpreter a chance to open next socket + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + fEventSocket = new Socket("localhost", eventPort); + fEventReader = new BufferedReader(new InputStreamReader(fEventSocket.getInputStream())); + } catch (UnknownHostException e) { + requestFailed("Unable to connect to PDA VM", e); + } catch (IOException e) { + requestFailed("Unable to connect to PDA VM", e); + } + fThread = new PDAThread(this); + fThreads = new IThread[] {fThread}; + fEventDispatch = new EventDispatchJob(); + fEventDispatch.schedule(); + IBreakpointManager breakpointManager = getBreakpointManager(); + breakpointManager.addBreakpointListener(this); + breakpointManager.addBreakpointManagerListener(this); + // initialize error hanlding to suspend on 'unimplemented instructions' + // and 'no such label' errors + sendRequest("eventstop unimpinstr 1"); + sendRequest("eventstop nosuchlabel 1"); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugTarget#getProcess() + */ + public IProcess getProcess() { + return fProcess; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugTarget#getThreads() + */ + public IThread[] getThreads() throws DebugException { + return fThreads; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads() + */ + public boolean hasThreads() throws DebugException { + return true; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugTarget#getName() + */ + public String getName() throws DebugException { + return "PDA"; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint) + */ + public boolean supportsBreakpoint(IBreakpoint breakpoint) { + if (!isTerminated() && breakpoint.getModelIdentifier().equals(getModelIdentifier())) { + try { + String program = getLaunch().getLaunchConfiguration().getAttribute(DebugCorePlugin.ATTR_PDA_PROGRAM, (String)null); + if (program != null) { + IResource resource = null; + if (breakpoint instanceof PDARunToLineBreakpoint) { + PDARunToLineBreakpoint rtl = (PDARunToLineBreakpoint) breakpoint; + resource = rtl.getSourceFile(); + } else { + IMarker marker = breakpoint.getMarker(); + if (marker != null) { + resource = marker.getResource(); + } + } + if (resource != null) { + IPath p = new Path(program); + return resource.getFullPath().equals(p); + } + } + } catch (CoreException e) { + } + } + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() + */ + public IDebugTarget getDebugTarget() { + return this; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() + */ + public ILaunch getLaunch() { + return fLaunch; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#canTerminate() + */ + public boolean canTerminate() { + return getProcess().canTerminate(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#isTerminated() + */ + public boolean isTerminated() { + return fTerminated || getProcess().isTerminated(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#terminate() + */ + public void terminate() throws DebugException { + getThread().terminate(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#canResume() + */ + public boolean canResume() { + return !isTerminated() && isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() + */ + public boolean canSuspend() { + return !isTerminated() && !isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() + */ + public boolean isSuspended() { + return !isTerminated() && getThread().isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#resume() + */ + public void resume() throws DebugException { + getThread().resume(); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#suspend() + */ + public void suspend() throws DebugException { + getThread().suspend(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint) + */ + public void breakpointAdded(IBreakpoint breakpoint) { + if (supportsBreakpoint(breakpoint)) { + try { + if ((breakpoint.isEnabled() && getBreakpointManager().isEnabled()) || !breakpoint.isRegistered()) { + PDALineBreakpoint pdaBreakpoint = (PDALineBreakpoint)breakpoint; + pdaBreakpoint.install(this); + } + } catch (CoreException e) { + } + } + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) + */ + public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { + if (supportsBreakpoint(breakpoint)) { + try { + PDALineBreakpoint pdaBreakpoint = (PDALineBreakpoint)breakpoint; + pdaBreakpoint.remove(this); + } catch (CoreException e) { + } + } + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) + */ + public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { + if (supportsBreakpoint(breakpoint)) { + try { + if (breakpoint.isEnabled() && getBreakpointManager().isEnabled()) { + breakpointAdded(breakpoint); + } else { + breakpointRemoved(breakpoint, null); + } + } catch (CoreException e) { + } + } + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect() + */ + public boolean canDisconnect() { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDisconnect#disconnect() + */ + public void disconnect() throws DebugException { + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected() + */ + public boolean isDisconnected() { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval() + */ + public boolean supportsStorageRetrieval() { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long) + */ + public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { + return null; + } + + /** + * Notification we have connected to the VM and it has started. + * Resume the VM. + */ + private void started() { + fireCreationEvent(); + installDeferredBreakpoints(); + try { + resume(); + } catch (DebugException e) { + } + } + + /** + * Install breakpoints that are already registered with the breakpoint + * manager. + */ + private void installDeferredBreakpoints() { + IBreakpoint[] breakpoints = getBreakpointManager().getBreakpoints(getModelIdentifier()); + for (int i = 0; i < breakpoints.length; i++) { + breakpointAdded(breakpoints[i]); + } + } + + /** + * Called when this debug target terminates. + */ + private synchronized void terminated() { + fTerminated = true; + fThread = null; + fThreads = new IThread[0]; + IBreakpointManager breakpointManager = getBreakpointManager(); + breakpointManager.removeBreakpointListener(this); + breakpointManager.removeBreakpointManagerListener(this); + fireTerminateEvent(); + removeEventListener(this); + } + + /** + * Returns the values on the data stack (top down) + * + * @return the values on the data stack (top down) + */ + public IValue[] getDataStack() throws DebugException { + String dataStack = sendRequest("data"); + if (dataStack != null && dataStack.length() > 0) { + String[] values = dataStack.split("\\|"); + IValue[] theValues = new IValue[values.length]; + for (int i = 0; i < values.length; i++) { + String value = values[values.length - i - 1]; + theValues[i] = new PDAStackValue(this, value, i); + } + return theValues; + } + return new IValue[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.examples.core.pda.model.PDADebugElement#sendRequest(java.lang.String) + */ + public String sendRequest(String request) throws DebugException { + synchronized (fRequestSocket) { + fRequestWriter.println(request); + fRequestWriter.flush(); + try { + // wait for reply + return fRequestReader.readLine(); + } catch (IOException e) { + requestFailed("Request failed: " + request, e); + } + } + return null; + } + + /** + * When the breakpoint manager disables, remove all registered breakpoints + * requests from the VM. When it enables, reinstall them. + */ + public void breakpointManagerEnablementChanged(boolean enabled) { + IBreakpoint[] breakpoints = getBreakpointManager().getBreakpoints(getModelIdentifier()); + for (int i = 0; i < breakpoints.length; i++) { + if (enabled) { + breakpointAdded(breakpoints[i]); + } else { + breakpointRemoved(breakpoints[i], null); + } + } + } + + /** + * Returns whether popping the data stack is currently permitted + * + * @return whether popping the data stack is currently permitted + */ + public boolean canPop() { + try { + return !isTerminated() && isSuspended() && getDataStack().length > 0; + } catch (DebugException e) { + } + return false; + } + + /** + * Pops and returns the top of the data stack + * + * @return the top value on the stack + * @throws DebugException if the stack is empty or the request fails + */ + public IValue pop() throws DebugException { + IValue[] dataStack = getDataStack(); + if (dataStack.length > 0) { + sendRequest("popdata"); + return dataStack[0]; + } + requestFailed("Empty stack", null); + return null; + } + + /** + * Returns whether pushing a value is currently supported. + * + * @return whether pushing a value is currently supported + */ + public boolean canPush() { + return !isTerminated() && isSuspended(); + } + + /** + * Pushes a value onto the stack. + * + * @param value value to push + * @throws DebugException on failure + */ + public void push(String value) throws DebugException { + sendRequest("pushdata " + value); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.examples.core.pda.model.IPDAEventListener#handleEvent(java.lang.String) + */ + public void handleEvent(String event) { + if (event.equals("started")) { + started(); + } else if (event.equals("terminated")) { + terminated(); + } + } + + /** + * Returns this debug target's single thread, or <code>null</code> + * if terminated. + * + * @return this debug target's single thread, or <code>null</code> + * if terminated + */ + public synchronized PDAThread getThread() { + return fThread; + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAStackFrame.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAStackFrame.java new file mode 100644 index 000000000..a3cbe43c8 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAStackFrame.java @@ -0,0 +1,251 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IRegisterGroup; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IVariable; + +/** + * PDA stack frame. + */ +public class PDAStackFrame extends PDADebugElement implements IStackFrame { + + private PDAThread fThread; + private String fName; + private int fPC; + private String fFileName; + private int fId; + + /** + * Constructs a stack frame in the given thread with the given + * frame data. + * + * @param thread + * @param data frame data + * @param id stack frame id (0 is the bottom of the stack) + */ + public PDAStackFrame(PDAThread thread, String data, int id) { + super(thread.getPDADebugTarget()); + fId = id; + fThread = thread; + init(data); + } + + /** + * Initializes this frame based on its data + * + * @param data + */ + private void init(String data) { + String[] strings = data.split("\\|"); + String fileName = strings[0]; + fFileName = (new Path(fileName)).lastSegment(); + String pc = strings[1]; + fPC = Integer.parseInt(pc) + 1; + fName = strings[2]; + int numVars = strings.length - 3; + IVariable[] vars = new IVariable[numVars]; + for (int i = 0; i < numVars; i++) { + vars[i] = new PDAVariable(this, strings[i + 3]); + } + fThread.setVariables(this, vars); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#getThread() + */ + public IThread getThread() { + return fThread; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#getVariables() + */ + public IVariable[] getVariables() throws DebugException { + return fThread.getVariables(this); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#hasVariables() + */ + public boolean hasVariables() throws DebugException { + return getVariables().length > 0; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#getLineNumber() + */ + public int getLineNumber() throws DebugException { + return fPC; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#getCharStart() + */ + public int getCharStart() throws DebugException { + return -1; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#getCharEnd() + */ + public int getCharEnd() throws DebugException { + return -1; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#getName() + */ + public String getName() throws DebugException { + return fName; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#getRegisterGroups() + */ + public IRegisterGroup[] getRegisterGroups() throws DebugException { + return null; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStackFrame#hasRegisterGroups() + */ + public boolean hasRegisterGroups() throws DebugException { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepInto() + */ + public boolean canStepInto() { + return getThread().canStepInto(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepOver() + */ + public boolean canStepOver() { + return getThread().canStepOver(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepReturn() + */ + public boolean canStepReturn() { + return getThread().canStepReturn(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#isStepping() + */ + public boolean isStepping() { + return getThread().isStepping(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepInto() + */ + public void stepInto() throws DebugException { + getThread().stepInto(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepOver() + */ + public void stepOver() throws DebugException { + getThread().stepOver(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepReturn() + */ + public void stepReturn() throws DebugException { + getThread().stepReturn(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#canResume() + */ + public boolean canResume() { + return getThread().canResume(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() + */ + public boolean canSuspend() { + return getThread().canSuspend(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() + */ + public boolean isSuspended() { + return getThread().isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#resume() + */ + public void resume() throws DebugException { + getThread().resume(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#suspend() + */ + public void suspend() throws DebugException { + getThread().suspend(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#canTerminate() + */ + public boolean canTerminate() { + return getThread().canTerminate(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#isTerminated() + */ + public boolean isTerminated() { + return getThread().isTerminated(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#terminate() + */ + public void terminate() throws DebugException { + getThread().terminate(); + } + + /** + * Returns the name of the source file this stack frame is associated + * with. + * + * @return the name of the source file this stack frame is associated + * with + */ + public String getSourceName() { + return fFileName; + } + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (obj instanceof PDAStackFrame) { + PDAStackFrame sf = (PDAStackFrame)obj; + return sf.getThread().equals(getThread()) && + sf.getSourceName().equals(getSourceName()) && + sf.fId == fId; + } + return false; + } + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return getSourceName().hashCode() + fId; + } + + /** + * Returns this stack frame's unique identifier within its thread + * + * @return this stack frame's unique identifier within its thread + */ + protected int getIdentifier() { + return fId; + } + + +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAStackValue.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAStackValue.java new file mode 100644 index 000000000..2f13211f4 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAStackValue.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +/** + * A value on the data stack + */ +public class PDAStackValue extends PDAValue { + + private int fIndex; + + /** + * Constructs a value that appears on the data stack + * + * @param target debug target + * @param value value on the stack + * @param index index on the stack + */ + public PDAStackValue(PDADebugTarget target, String value, int index) { + super(target, value); + fIndex = index; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + return super.equals(obj) && ((PDAStackValue)obj).fIndex == fIndex; + } + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return super.hashCode() + fIndex; + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAThread.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAThread.java new file mode 100644 index 000000000..6a4102ac3 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAThread.java @@ -0,0 +1,426 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IStackFrame; +import org.eclipse.debug.core.model.IThread; +import org.eclipse.debug.core.model.IVariable; + +/** + * A PDA thread. A PDA VM is single threaded. + */ +public class PDAThread extends PDADebugElement implements IThread, IPDAEventListener { + + /** + * Breakpoint this thread is suspended at or <code>null</code> + * if none. + */ + private IBreakpoint fBreakpoint; + + /** + * Whether this thread is stepping + */ + private boolean fStepping = false; + + /** + * Wether this thread is suspended + */ + private boolean fSuspended = false; + + /** + * Most recent error event or <code>null</code> + */ + private String fErrorEvent; + + /** + * Table mapping stack frames to current variables + */ + private Map fVariables = new HashMap(); + + /** + * Constructs a new thread for the given target + * + * @param target VM + */ + public PDAThread(PDADebugTarget target) { + super(target); + getPDADebugTarget().addEventListener(this); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getStackFrames() + */ + public IStackFrame[] getStackFrames() throws DebugException { + if (isSuspended()) { + String framesData = sendRequest("stack"); + if (framesData != null) { + String[] frames = framesData.split("#"); + IStackFrame[] theFrames = new IStackFrame[frames.length]; + for (int i = 0; i < frames.length; i++) { + String data = frames[i]; + theFrames[frames.length - i - 1] = new PDAStackFrame(this, data, i); + } + return theFrames; + } + } + return new IStackFrame[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#hasStackFrames() + */ + public boolean hasStackFrames() throws DebugException { + return isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getPriority() + */ + public int getPriority() throws DebugException { + return 0; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getTopStackFrame() + */ + public IStackFrame getTopStackFrame() throws DebugException { + IStackFrame[] frames = getStackFrames(); + if (frames.length > 0) { + return frames[0]; + } + return null; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getName() + */ + public String getName() { + return "Main thread"; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IThread#getBreakpoints() + */ + public IBreakpoint[] getBreakpoints() { + if (fBreakpoint == null) { + return new IBreakpoint[0]; + } + return new IBreakpoint[]{fBreakpoint}; + } + + /** + * Notifies this thread it has been suspended by the given breakpoint. + * + * @param breakpoint breakpoint + */ + public void suspendedBy(IBreakpoint breakpoint) { + fBreakpoint = breakpoint; + suspended(DebugEvent.BREAKPOINT); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#canResume() + */ + public boolean canResume() { + return isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() + */ + public boolean canSuspend() { + return !isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() + */ + public boolean isSuspended() { + return fSuspended && !isTerminated(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#resume() + */ + public void resume() throws DebugException { + //#ifdef ex2 +//# // TODO: Exercise 2 - send resume request to interpreter + //#else + sendRequest("resume"); + //#endif + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ISuspendResume#suspend() + */ + public void suspend() throws DebugException { + //#ifdef ex2 +//# // TODO: Exercise 2 - send suspend request to interpreter + //#else + sendRequest("suspend"); + //#endif + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepInto() + */ + public boolean canStepInto() { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepOver() + */ + public boolean canStepOver() { + return isSuspended(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#canStepReturn() + */ + public boolean canStepReturn() { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#isStepping() + */ + public boolean isStepping() { + return fStepping; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepInto() + */ + public void stepInto() throws DebugException { + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepOver() + */ + public void stepOver() throws DebugException { + sendRequest("step"); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IStep#stepReturn() + */ + public void stepReturn() throws DebugException { + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#canTerminate() + */ + public boolean canTerminate() { + return !isTerminated(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#isTerminated() + */ + public boolean isTerminated() { + return getDebugTarget().isTerminated(); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ITerminate#terminate() + */ + public void terminate() throws DebugException { + //#ifdef ex2 +//# // TODO: Exercise 2 - send termination request to interpreter + //#else + sendRequest("exit"); + //#endif + } + + /** + * Sets whether this thread is stepping + * + * @param stepping whether stepping + */ + private void setStepping(boolean stepping) { + fStepping = stepping; + } + + /** + * Sets whether this thread is suspended + * + * @param suspended whether suspended + */ + private void setSuspended(boolean suspended) { + fSuspended = suspended; + } + + /** + * Sets the most recent error event encountered, or <code>null</code> + * to clear the most recent error + * + * @param event one of 'unimpinstr' or 'nosuchlabel' or <code>null</code> + */ + private void setError(String event) { + fErrorEvent = event; + } + + /** + * Returns the most revent error event encountered since the last + * suspend, or <code>null</code> if none. + * + * @return the most revent error event encountered since the last + * suspend, or <code>null</code> if none + */ + public Object getError() { + return fErrorEvent; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.examples.core.pda.model.IPDAEventListener#handleEvent(java.lang.String) + */ + public void handleEvent(String event) { + // clear previous state + fBreakpoint = null; + setStepping(false); + + // handle events + if (event.startsWith("resumed")) { + setSuspended(false); + if (event.endsWith("step")) { + setStepping(true); + resumed(DebugEvent.STEP_OVER); + //#ifdef ex2 +//# } +//# // TODO: Exercise 2 - handle/fire "client" resume event + //#else + } else if (event.endsWith("client")) { + resumed(DebugEvent.CLIENT_REQUEST); + } + //#endif + //#ifdef ex5 +//# // TODO: Exercise 5 - handle start of drop event + //#else + else if (event.endsWith("drop")) { + resumed(DebugEvent.STEP_RETURN); + } + //#endif + } else if (event.startsWith("suspended")) { + setSuspended(true); + //#ifdef ex2 +//# // TODO: Exercise 2 - handle/fire "client" suspend event +//# if (event.endsWith("step")) { +//# suspended(DebugEvent.STEP_END); +//# } else if (event.startsWith("suspended event") && getError() != null) { +//# exceptionHit(); +//# } + //#else + if (event.endsWith("client")) { + suspended(DebugEvent.CLIENT_REQUEST); + } else if (event.endsWith("step")) { + suspended(DebugEvent.STEP_END); + } else if (event.startsWith("suspended event") && getError() != null) { + exceptionHit(); + } + //#endif + //#ifdef ex5 +//# // TODO: Exercise 5 - handle end of drop event + //#else + else if (event.endsWith("drop")) { + suspended(DebugEvent.STEP_END); + } + //#endif + } else if (event.equals("started")) { + fireCreationEvent(); + } else { + setError(event); + } + + } + + /** + * Notification the target has resumed for the given reason. + * Clears any error condition that was last encountered and + * fires a resume event, and clears all cached variables + * for stack frames. + * + * @param detail reason for the resume + */ + private void resumed(int detail) { + setError(null); + synchronized (fVariables) { + fVariables.clear(); + } + fireResumeEvent(detail); + } + + /** + * Notification the target has suspended for the given reason + * + * @param detail reason for the suspend + */ + private void suspended(int detail) { + fireSuspendEvent(detail); + } + + /** + * Notification an error was encountered. Fires a breakpoint + * suspend event. + */ + private void exceptionHit() { + suspended(DebugEvent.BREAKPOINT); + } + + /** + * Sets the current variables for the given stack frame. Called + * by PDA stack frame when it is created. + * + * @param frame + * @param variables + */ + protected void setVariables(IStackFrame frame, IVariable[] variables) { + synchronized (fVariables) { + fVariables.put(frame, variables); + } + } + + /** + * Returns the current variables for the given stack frame, or + * <code>null</code> if none. + * + * @param frame stack frame + * @return variables or <code>null</code> + */ + protected IVariable[] getVariables(IStackFrame frame) { + synchronized (fVariables) { + IVariable[] variables = (IVariable[]) fVariables.get(frame); + if (variables == null) { + return new IVariable[0]; + } + return variables; + } + } + + /** + * Pops the top frame off the callstack. + * + * @throws DebugException + */ + public void pop() throws DebugException { + //#ifdef ex5 +//# // TODO: Exercise 5 - send drop request + //#else + sendRequest("drop"); + //#endif + } + + /** + * Returns whether this thread can pop the top stack frame. + * + * @return whether this thread can pop the top stack frame + */ + public boolean canPop() { + //#ifdef ex5 +//# // TODO: Exercise 5 - allow pop if there is more than 1 frame on the stack + //#else + try { + return getStackFrames().length > 1; + } catch (DebugException e) { + } + //#endif + return false; + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAValue.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAValue.java new file mode 100644 index 000000000..e871004af --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAValue.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.IVariable; + +/** + * Value of a PDA variable. + */ +public class PDAValue extends PDADebugElement implements IValue { + + private String fValue; + + public PDAValue(PDADebugTarget target, String value) { + super(target); + fValue = value; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValue#getReferenceTypeName() + */ + public String getReferenceTypeName() throws DebugException { + try { + Integer.parseInt(fValue); + } catch (NumberFormatException e) { + return "text"; + } + return "integer"; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValue#getValueString() + */ + public String getValueString() throws DebugException { + return fValue; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValue#isAllocated() + */ + public boolean isAllocated() throws DebugException { + return true; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValue#getVariables() + */ + public IVariable[] getVariables() throws DebugException { + return new IVariable[0]; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValue#hasVariables() + */ + public boolean hasVariables() throws DebugException { + return fValue.split("\\W+").length > 1; + } + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + return obj instanceof PDAValue && ((PDAValue)obj).fValue.equals(fValue); + } + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return fValue.hashCode(); + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAVariable.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAVariable.java new file mode 100644 index 000000000..c57a9d24a --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/PDAVariable.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.IVariable; + +/** + * A variable in a PDA stack frame + */ +public class PDAVariable extends PDADebugElement implements IVariable { + + // name & stack frmae + private String fName; + private PDAStackFrame fFrame; + + /** + * Constructs a variable contained in the given stack frame + * with the given name. + * + * @param frame owning stack frame + * @param name variable name + */ + public PDAVariable(PDAStackFrame frame, String name) { + super(frame.getPDADebugTarget()); + fFrame = frame; + fName = name; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IVariable#getValue() + */ + public IValue getValue() throws DebugException { + String value = sendRequest("var " + getStackFrame().getIdentifier() + " " + getName()); + return new PDAValue(this.getPDADebugTarget(), value); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IVariable#getName() + */ + public String getName() throws DebugException { + return fName; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IVariable#getReferenceTypeName() + */ + public String getReferenceTypeName() throws DebugException { + return "Thing"; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IVariable#hasValueChanged() + */ + public boolean hasValueChanged() throws DebugException { + return false; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#setValue(java.lang.String) + */ + public void setValue(String expression) throws DebugException { + sendRequest("setvar " + getStackFrame().getIdentifier() + " " + getName() + " " + expression); + fireChangeEvent(DebugEvent.CONTENT); + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#setValue(org.eclipse.debug.core.model.IValue) + */ + public void setValue(IValue value) throws DebugException { + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#supportsValueModification() + */ + public boolean supportsValueModification() { + return true; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#verifyValue(java.lang.String) + */ + public boolean verifyValue(String expression) throws DebugException { + return true; + } + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.IValueModification#verifyValue(org.eclipse.debug.core.model.IValue) + */ + public boolean verifyValue(IValue value) throws DebugException { + return false; + } + + /** + * Returns the stack frame owning this variable. + * + * @return the stack frame owning this variable + */ + protected PDAStackFrame getStackFrame() { + return fFrame; + } + +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/WordStructureDelegate.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/WordStructureDelegate.java new file mode 100644 index 000000000..dbb06cb22 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/model/WordStructureDelegate.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.model; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.ILogicalStructureTypeDelegate; +import org.eclipse.debug.core.model.IValue; + +/** + * Logical stucture to translate a string into its words. + */ +public class WordStructureDelegate implements ILogicalStructureTypeDelegate { + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate#providesLogicalStructure(org.eclipse.debug.core.model.IValue) + */ + public boolean providesLogicalStructure(IValue value) { + //#ifdef ex6 +//# // TODO: Exercise 6 - provide logical structures if the value has multiple words + //#else + try { + String string = value.getValueString(); + String[] words = string.split("\\W+"); + return words.length > 1; + } catch (DebugException e) { + } + //#endif + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate#getLogicalStructure(org.eclipse.debug.core.model.IValue) + */ + public IValue getLogicalStructure(IValue value) throws CoreException { + //#ifdef ex6 +//# // TODO: Exercise 6 - create an array from the given value +//# return null; + //#else + return new PDAArray((PDAValue)value); + //#endif + } + +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourceLookupDirector.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourceLookupDirector.java new file mode 100644 index 000000000..f975cf7c3 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourceLookupDirector.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.sourcelookup; + +import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector; +import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant; + +/** + * PDA source lookup director. For PDA source lookup there is one source + * lookup participant. + */ +public class PDASourceLookupDirector extends AbstractSourceLookupDirector { + /* (non-Javadoc) + * @see org.eclipse.debug.internal.core.sourcelookup.ISourceLookupDirector#initializeParticipants() + */ + public void initializeParticipants() { + //#ifdef ex4 +//# // TODO: Exercise 4 - add our participant to this director + //#else + addParticipants(new ISourceLookupParticipant[]{new PDASourceLookupParticipant()}); + //#endif + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourceLookupParticipant.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourceLookupParticipant.java new file mode 100644 index 000000000..0d07ce78d --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourceLookupParticipant.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.sourcelookup; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupParticipant; +import org.eclipse.debug.examples.core.pda.model.PDAStackFrame; + + +/** + * The PDA source lookup participant knows how to translate a + * PDA stack frame into a source file name + */ +public class PDASourceLookupParticipant extends AbstractSourceLookupParticipant { + /* (non-Javadoc) + * @see org.eclipse.debug.internal.core.sourcelookup.ISourceLookupParticipant#getSourceName(java.lang.Object) + */ + public String getSourceName(Object object) throws CoreException { + //#ifdef ex4 +//# // TODO: Exercise 4 - return the name of the source file for the given stack frame +//# return null; + //#else + if (object instanceof PDAStackFrame) { + return ((PDAStackFrame)object).getSourceName(); + } + return null; + //#endif + } +} diff --git a/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourcePathComputerDelegate.java b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourcePathComputerDelegate.java new file mode 100644 index 000000000..d91b3f245 --- /dev/null +++ b/org.eclipse.debug.examples.core/src/org/eclipse/debug/examples/core/pda/sourcelookup/PDASourcePathComputerDelegate.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 IBM Corporation 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: + * IBM Corporation - initial API and implementation + * Bjorn Freeman-Benson - initial API and implementation + *******************************************************************************/ +package org.eclipse.debug.examples.core.pda.sourcelookup; + +import org.eclipse.core.resources.IContainer; +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.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.sourcelookup.ISourceContainer; +import org.eclipse.debug.core.sourcelookup.ISourcePathComputerDelegate; +import org.eclipse.debug.core.sourcelookup.containers.FolderSourceContainer; +import org.eclipse.debug.core.sourcelookup.containers.ProjectSourceContainer; +import org.eclipse.debug.core.sourcelookup.containers.WorkspaceSourceContainer; +import org.eclipse.debug.examples.core.pda.DebugCorePlugin; + + +/** + * Computes the default source lookup path for a PDA launch configuration. + * The default source lookup path is the folder or project containing + * the PDA program being launched. If the program is not specified, the workspace + * is searched by default. + */ +public class PDASourcePathComputerDelegate implements ISourcePathComputerDelegate { + + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.core.sourcelookup.ISourcePathComputerDelegate#computeSourceContainers(org.eclipse.debug.core.ILaunchConfiguration, org.eclipse.core.runtime.IProgressMonitor) + */ + public ISourceContainer[] computeSourceContainers(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException { + String path = configuration.getAttribute(DebugCorePlugin.ATTR_PDA_PROGRAM, (String)null); + ISourceContainer sourceContainer = null; + if (path != null) { + IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(path)); + if (resource != null) { + //#ifdef ex4 +//# // TODO: Exercise 4 - seed the source lookup path + //#else + IContainer container = resource.getParent(); + if (container.getType() == IResource.PROJECT) { + sourceContainer = new ProjectSourceContainer((IProject)container, false); + } else if (container.getType() == IResource.FOLDER) { + sourceContainer = new FolderSourceContainer(container, false); + } + //#endif + } + } + if (sourceContainer == null) { + sourceContainer = new WorkspaceSourceContainer(); + } + return new ISourceContainer[]{sourceContainer}; + } +} |