diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.dsf.debug.ui/META-INF/MANIFEST.MF index c768637b570..1a96a0189b8 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.dd.dsf.debug.ui/META-INF/MANIFEST.MF @@ -12,6 +12,8 @@ Require-Bundle: org.eclipse.ui, org.eclipse.debug.core, org.eclipse.debug.ui, org.eclipse.ui.ide, + org.eclipse.jface.text, + org.eclipse.ui.workbench.texteditor, org.eclipse.dd.dsf, org.eclipse.dd.dsf.ui, org.eclipse.dd.dsf.debug, @@ -24,5 +26,7 @@ Export-Package: org.eclipse.dd.dsf.debug.ui.viewmodel.formatsupport, org.eclipse.dd.dsf.debug.ui.viewmodel.launch, org.eclipse.dd.dsf.debug.ui.viewmodel.register, - org.eclipse.dd.dsf.debug.ui.viewmodel.variable + org.eclipse.dd.dsf.debug.ui.viewmodel.variable, + org.eclipse.dd.dsf.debug.ui.sourcelookup, + org.eclipse.dd.dsf.debug.ui.actions Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/plugin.xml b/plugins/org.eclipse.dd.dsf.debug.ui/plugin.xml index 614503dc5b9..ec8c6e8158e 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/plugin.xml +++ b/plugins/org.eclipse.dd.dsf.debug.ui/plugin.xml @@ -7,4 +7,50 @@ delegateClass="org.eclipse.dd.dsf.debug.ui.viewmodel.expression.WatchExpressionDelegate"/> + + + + + + + + + + + + + + + + diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfCommandRunnable.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfCommandRunnable.java new file mode 100644 index 00000000000..d77cfa1a26d --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfCommandRunnable.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.actions; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.debug.service.INativeProcesses; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IStepQueueManager; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode; +import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext; +import org.eclipse.debug.core.commands.IDebugCommandRequest; + +@SuppressWarnings("restriction") +@Immutable +public abstract class DsfCommandRunnable extends DsfRunnable { + private final IExecutionDMContext fContext; + private final DsfServicesTracker fTracker; + private final IDebugCommandRequest fRequest; + + public IExecutionDMContext getContext() { return fContext; } + public IRunControl getRunControl() { + return fTracker.getService(IRunControl.class); + } + public IStepQueueManager getStepQueueMgr() { + return fTracker.getService(IStepQueueManager.class); + } + + public INativeProcesses getProcesses() { + return fTracker.getService(INativeProcesses.class); + } + + public DsfCommandRunnable(DsfServicesTracker servicesTracker, Object element, IDebugCommandRequest request) { + fTracker = servicesTracker; + if (element instanceof DMVMContext) { + // Javac doesn't like the cast to "(AbstractDMVMLayoutNode.DMVMContext)" need to use the + // construct below and suppress warnings. + @SuppressWarnings("unchecked") + AbstractDMVMLayoutNode.DMVMContext vmc = (AbstractDMVMLayoutNode.DMVMContext)element; + fContext = DMContexts.getAncestorOfType(vmc.getDMC(), IExecutionDMContext.class); + } else { + fContext = null; + } + + fRequest = request; + } + + public final void run() { + if (fRequest.isCanceled()) return; + if (getContext() == null) { + fRequest.setStatus(makeError("Selected object does not support run control.", null)); //$NON-NLS-1$ + } else if (getRunControl() == null) { + fRequest.setStatus(makeError("Run Control not available", null)); //$NON-NLS-1$ + } else { + doExecute(); + } + fRequest.done(); + } + + /** + * Method to perform the actual work. It should not call monitor.done(), because + * it will be called in the super-class. + */ + protected abstract void doExecute(); + + protected IStatus makeError(String message, Throwable e) { + return new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, -1, message, e); + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfResumeCommand.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfResumeCommand.java new file mode 100644 index 00000000000..23adc2644d4 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfResumeCommand.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.actions; + +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.IResumeHandler; + +@Immutable +public class DsfResumeCommand implements IResumeHandler { + + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public DsfResumeCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + public void canExecute(final IEnabledStateRequest request) { + if (request.getElements().length != 1) { + request.setEnabled(false); + request.done(); + return; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + request.setEnabled(getRunControl().canResume(getContext())); + } + }); + } + + public boolean execute(final IDebugCommandRequest request) { + if (request.getElements().length != 1) { + request.done(); + return false; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + getRunControl().resume(getContext(), new RequestMonitor(fExecutor, null)); + } + }); + return false; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepIntoCommand.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepIntoCommand.java new file mode 100644 index 00000000000..16c1b183d48 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepIntoCommand.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.actions; + +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.StepType; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.IStepIntoHandler; + +@Immutable +public class DsfStepIntoCommand implements IStepIntoHandler { + + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public DsfStepIntoCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + public void canExecute(final IEnabledStateRequest request) { + if (request.getElements().length != 1) { + request.setEnabled(false); + request.done(); + return; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + request.setEnabled(getStepQueueMgr().canEnqueueStep(getContext())); + } + }); + } + + public boolean execute(final IDebugCommandRequest request) { + if (request.getElements().length != 1) { + request.done(); + return false; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + getStepQueueMgr().enqueueStep(getContext(), StepType.STEP_INTO); + } + }); + return true; + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepOverCommand.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepOverCommand.java new file mode 100644 index 00000000000..6881453e80d --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepOverCommand.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.actions; + +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.StepType; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.IStepIntoHandler; + +@Immutable +public class DsfStepOverCommand implements IStepIntoHandler { + + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public DsfStepOverCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + public void canExecute(final IEnabledStateRequest request) { + if (request.getElements().length != 1) { + request.setEnabled(false); + request.done(); + return; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + request.setEnabled(getStepQueueMgr().canEnqueueStep(getContext())); + } + }); + } + + public boolean execute(final IDebugCommandRequest request) { + if (request.getElements().length != 1) { + request.done(); + return false; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + getStepQueueMgr().enqueueStep(getContext(), StepType.STEP_OVER); + } + }); + return true; + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepReturnCommand.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepReturnCommand.java new file mode 100644 index 00000000000..0e179cebc19 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfStepReturnCommand.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.actions; + +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.StepType; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.IStepIntoHandler; + +@Immutable +public class DsfStepReturnCommand implements IStepIntoHandler { + + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public DsfStepReturnCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + public void canExecute(final IEnabledStateRequest request) { + if (request.getElements().length != 1) { + request.setEnabled(false); + request.done(); + return; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + request.setEnabled(getStepQueueMgr().canEnqueueStep(getContext())); + } + }); + } + + public boolean execute(final IDebugCommandRequest request) { + if (request.getElements().length != 1) { + request.done(); + return false; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + getStepQueueMgr().enqueueStep(getContext(), StepType.STEP_RETURN); + } + }); + return true; + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfSuspendCommand.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfSuspendCommand.java new file mode 100644 index 00000000000..882d165fe09 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfSuspendCommand.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.actions; + +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.ISuspendHandler; + +@Immutable +public class DsfSuspendCommand implements ISuspendHandler { + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public DsfSuspendCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + public void canExecute(final IEnabledStateRequest request) { + if (request.getElements().length != 1) { + request.setEnabled(false); + request.done(); + return; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + request.setEnabled(getRunControl().canSuspend(getContext())); + } + }); + } + + public boolean execute(final IDebugCommandRequest request) { + if (request.getElements().length != 1) { + request.done(); + return false; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + getRunControl().suspend(getContext(), new RequestMonitor(fExecutor, null)); + } + }); + return false; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfTerminateCommand.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfTerminateCommand.java new file mode 100644 index 00000000000..5f1af3cd6a9 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/actions/DsfTerminateCommand.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.actions; + +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.debug.service.INativeProcesses; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode; +import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.ITerminateHandler; + +public class DsfTerminateCommand implements ITerminateHandler { + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public DsfTerminateCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + // Run control may not be avilable after a connection is terminated and shut down. + public void canExecute(final IEnabledStateRequest request) { + if (request.getElements().length != 1 || + !(request.getElements()[0] instanceof DMVMContext) ) + { + request.setEnabled(false); + request.done(); + return; + } + + // Javac doesn't like the cast to "(AbstractDMVMLayoutNode.DMVMContext)" need to use the + // construct below and suppress warnings. + @SuppressWarnings("unchecked") + AbstractDMVMLayoutNode.DMVMContext vmc = (AbstractDMVMLayoutNode.DMVMContext)request.getElements()[0]; + final IExecutionDMContext dmc = DMContexts.getAncestorOfType(vmc.getDMC(), IExecutionDMContext.class); + if (dmc == null) { + request.setEnabled(false); + request.done(); + return; + } + + fExecutor.execute( + new DsfRunnable() { + public void run() { + // Get the processes service and the exec context. + INativeProcesses processes = fTracker.getService(INativeProcesses.class); + if (processes == null || dmc == null) { + // Context or service already invalid. + request.done(); + } else { + // Check the teriminate. + processes.canTerminate( + processes.getThreadForExecutionContext(dmc), + new DataRequestMonitor(fExecutor, null) { + @Override + public void handleCompleted() { + request.setEnabled(getData()); + request.done(); + } + }); + } + } + }); + } + + public boolean execute(final IDebugCommandRequest request) { + if (request.getElements().length != 1) { + request.done(); + return false; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + getProcesses().terminate( + getProcesses().getThreadForExecutionContext(getContext()), new RequestMonitor(fExecutor, null)); + } + }); + return false; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/InstructionPointerImageProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/InstructionPointerImageProvider.java new file mode 100644 index 00000000000..4c3d3bc6c99 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/InstructionPointerImageProvider.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + *******************************************************************************/ + +package org.eclipse.dd.dsf.debug.ui.sourcelookup; + +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.debug.ui.sourcelookup.InstructionPointerManager.IPAnnotation; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.texteditor.IAnnotationImageProvider; + +@ThreadSafe +public class InstructionPointerImageProvider implements IAnnotationImageProvider { + + /* (non-Javadoc) + * @see org.eclipse.ui.texteditor.IAnnotationImageProvider#getManagedImage(org.eclipse.jface.text.source.Annotation) + */ + public Image getManagedImage(Annotation annotation) { + return ((IPAnnotation)annotation).getImage(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.texteditor.IAnnotationImageProvider#getImageDescriptorId(org.eclipse.jface.text.source.Annotation) + */ + public String getImageDescriptorId(Annotation annotation) { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.texteditor.IAnnotationImageProvider#getImageDescriptor(java.lang.String) + */ + public ImageDescriptor getImageDescriptor(String imageDescritporId) { + return null; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/InstructionPointerManager.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/InstructionPointerManager.java new file mode 100644 index 00000000000..d24ddce5c3a --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/InstructionPointerManager.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 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 + * Wind River Systems - Adapter to use with DSF + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.sourcelookup; + + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IStack; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.texteditor.IDocumentProvider; +import org.eclipse.ui.texteditor.ITextEditor; + +/** + * This class tracks instruction pointer contexts for a single DSF session. + */ +@ThreadSafe +class InstructionPointerManager { + + /** + * Editor annotation object for instruction pointers. + */ + static class IPAnnotation extends Annotation { + + /** The image for this annotation. */ + private Image fImage; + + /** Frame DMC that this IP is for **/ + private IStack.IFrameDMContext fFrame; + + /** + * Constructs an instruction pointer image. + * + * @param frame stack frame the instruction pointer is associated with + * @param annotationType the type of annotation to display (annotation identifier) + * @param text the message to display with the annotation as hover help + * @param image the image used to display the annotation + */ + IPAnnotation(IStack.IFrameDMContext frame, String annotationType, String text, Image image) { + super(annotationType, false, text); + fFrame = frame; + fImage = image; + } + + /** + * Returns this annotation's image. + * + * @return image + */ + protected Image getImage() { + return fImage; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object other) { + if (other instanceof IPAnnotation) { + return fFrame.equals(((IPAnnotation)other).fFrame); + } + return false; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return fFrame.hashCode(); + } + + } + + /** + * Represents the context for a single instruction pointer. This is a convenience class + * used to store the three objects that comprise an instruction pointer 'context' so it + * can be stored in collections. + */ + static class AnnotationWrapper { + + /** The text editor for this context. */ + private ITextEditor fTextEditor; + + /** Stack frame that this annotation is for */ + private IStack.IFrameDMContext fFrameDmc; + + /** The vertical ruler annotation for this context. */ + private Annotation fAnnotation; + + AnnotationWrapper(ITextEditor textEditor, Annotation annotation, IStack.IFrameDMContext frameDmc) { + fTextEditor = textEditor; + fAnnotation = annotation; + fFrameDmc = frameDmc; + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object other) { + if (other instanceof AnnotationWrapper) { + AnnotationWrapper otherContext = (AnnotationWrapper) other; + return getAnnotation().equals(otherContext.getAnnotation()); + } + return false; + } + + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return getAnnotation().hashCode(); + } + + ITextEditor getTextEditor() { return fTextEditor; } + Annotation getAnnotation() { return fAnnotation; } + IStack.IFrameDMContext getFrameDMC() { return fFrameDmc; } + } + + /** + * Mapping of IDebugTarget objects to (mappings of IThread objects to lists of instruction + * pointer contexts). + */ + private List fAnnotationWrappers; + + /** + * Clients must not instantiate this class. + */ + public InstructionPointerManager() { + fAnnotationWrappers = Collections.synchronizedList(new LinkedList()); + } + + /** + * Add an instruction pointer annotation in the specified editor for the + * specified stack frame. + */ + public void addAnnotation(ITextEditor textEditor, IStack.IFrameDMContext frame, Position position, boolean isTopFrame) { + + IDocumentProvider docProvider = textEditor.getDocumentProvider(); + IEditorInput editorInput = textEditor.getEditorInput(); + // If there is no annotation model, there's nothing more to do + IAnnotationModel annModel = docProvider.getAnnotationModel(editorInput); + if (annModel == null) { + return; + } + + String id; + String text; + Image image; + if (isTopFrame) { + id = "org.eclipse.dd.debug.currentIP"; //$NON-NLS-1$ + text = "Debug Current Instruction Pointer"; //$NON-NLS-1$ + image = DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_INSTRUCTION_POINTER_TOP); + } else { + id = "org.eclipse.dd.debug.secondaryIP"; //$NON-NLS-1$ + text = "Debug Call Stack"; //$NON-NLS-1$ + image = DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_INSTRUCTION_POINTER); + } + + Annotation annotation = new IPAnnotation(frame, id, text, image); + + // Add the annotation at the position to the editor's annotation model. + annModel.removeAnnotation(annotation); + annModel.addAnnotation(annotation, position); + + // Add to list of existing wrappers + fAnnotationWrappers.add(new AnnotationWrapper(textEditor, annotation, frame)); + } + + /** + * Remove all annotations associated with the specified debug target that this class + * is tracking. + */ + public void removeAnnotations(IRunControl.IExecutionDMContext execDmc) { + // Retrieve the mapping of threads to context lists + synchronized(fAnnotationWrappers) { + for (Iterator wrapperItr = fAnnotationWrappers.iterator(); wrapperItr.hasNext();) { + AnnotationWrapper wrapper = wrapperItr.next(); + if (DMContexts.isAncestorOf(wrapper.getFrameDMC(), execDmc)) { + removeAnnotation(wrapper.getTextEditor(), wrapper.getAnnotation()); + wrapperItr.remove(); + } + } + } + } + + /** Removes all annotations tracked by this manager */ + public void removeAllAnnotations() { + synchronized(fAnnotationWrappers) { + for (AnnotationWrapper wrapper : fAnnotationWrappers) { + removeAnnotation(wrapper.getTextEditor(), wrapper.getAnnotation()); + } + fAnnotationWrappers.clear(); + } + } + + /** + * Remove the specified annotation from the specified text editor. + */ + private void removeAnnotation(ITextEditor textEditor, Annotation annotation) { + IDocumentProvider docProvider = textEditor.getDocumentProvider(); + if (docProvider != null) { + IAnnotationModel annotationModel = docProvider.getAnnotationModel(textEditor.getEditorInput()); + if (annotationModel != null) { + annotationModel.removeAnnotation(annotation); + } + } + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/MISourceDisplayAdapter.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/MISourceDisplayAdapter.java new file mode 100644 index 00000000000..38cab0bd740 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/MISourceDisplayAdapter.java @@ -0,0 +1,552 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.sourcelookup; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IStack; +import org.eclipse.dd.dsf.debug.service.IStepQueueManager; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMData; +import org.eclipse.dd.dsf.debug.sourcelookup.DsfMISourceLookupParticipant; +import org.eclipse.dd.dsf.debug.ui.DsfDebugUIPlugin; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode.DMVMContext; +import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; +import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.debug.ui.sourcelookup.CommonSourceNotFoundEditorInput; +import org.eclipse.debug.ui.sourcelookup.ISourceDisplay; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Position; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorRegistry; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.progress.UIJob; +import org.eclipse.ui.texteditor.IDocumentProvider; +import org.eclipse.ui.texteditor.ITextEditor; + +/** + * Source display adapter that performs the source lookup, opens the editor, + * and paints the IP for the given object. + *

+ * The implementation relies on three types of jobs to perform the operations.
+ * - The first kind, "lookup job" performs the source lookup operation.
+ * - The second "display job" positions and annotates the editor.
+ * - The third clears the old IP annotations when a thread or process has resumed + * or exited. + *

+ * The the lookup jobs can run in parallel with the display or the clearing job, + * but the clearing job and the display job must not run at the same time. + * Hence there is some involved logic which ensures that the jobs are run in + * proper order. To avoid race conditions, this logic uses the session's + * dispatch thread to synchronize access to the state data of the running jobs. + */ +@ThreadSafe +@SuppressWarnings("restriction") +public class MISourceDisplayAdapter implements ISourceDisplay +{ + /** + * A job to perform source lookup on the given DMC. + */ + class LookupJob extends Job { + + private IDMContext fDmc; + private IWorkbenchPage fPage; + + /** + * Constructs a new source lookup job. + */ + public LookupJob(IDMContext dmc, IWorkbenchPage page) { + super("DSF Source Lookup"); //$NON-NLS-1$ + setPriority(Job.INTERACTIVE); + setSystem(true); + fDmc = dmc; + fPage = page; + } + + IDMContext getDmc() { return fDmc; } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + protected IStatus run(final IProgressMonitor monitor) { + if (monitor.isCanceled()) { + return Status.CANCEL_STATUS; + } + + final SourceLookupResult result = performLookup(); + executeFromJob(new DsfRunnable() { public void run() { + if (!monitor.isCanceled()) { + fPrevResult = result; + fPrevModelContext = fDmc; + fRunningLookupJob = null; + startDisplayJob(fPrevResult, fPage); + } + }}); + return Status.OK_STATUS; + } + + private SourceLookupResult performLookup() { + SourceLookupResult result = new SourceLookupResult(fDmc, null, null, null); + String editorId = null; + IEditorInput editorInput = null; + Object sourceElement = fSourceLookup.getSourceElement(fDmc); + + if (sourceElement == null) { + editorInput = new CommonSourceNotFoundEditorInput(fDmc); + editorId = IDebugUIConstants.ID_COMMON_SOURCE_NOT_FOUND_EDITOR; + } else if (sourceElement instanceof IFile) { + editorId = getEditorIdForFilename(((IFile)sourceElement).getName()); + editorInput = new FileEditorInput((IFile)sourceElement); + } + result.setEditorInput(editorInput); + result.setEditorId(editorId); + result.setSourceElement(sourceElement); + + return result; + } + + private String getEditorIdForFilename(String filename) { + IEditorRegistry registry = PlatformUI.getWorkbench().getEditorRegistry(); + IEditorDescriptor descriptor = registry.getDefaultEditor(filename); + if (descriptor == null) { + return "org.eclipse.ui.DefaultTextEditor"; //$NON-NLS-1$ + } + + return descriptor.getId(); + } + } + + /** + * Job that positions the editor and paints the IP Annotation for given DMC. + */ + class DisplayJob extends UIJob { + private SourceLookupResult fResult; + private IWorkbenchPage fPage; + + IDMContext getDmc() { return fResult.getDmc(); } + + /** + * Constructs a new source display job + */ + public DisplayJob(SourceLookupResult result, IWorkbenchPage page) { + super("Debug Source Display"); //$NON-NLS-1$ + setSystem(true); + setPriority(Job.INTERACTIVE); + fResult = result; + fPage = page; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public IStatus runInUIThread(final IProgressMonitor monitor) { + DsfRunnable displayJobFinishedRunnable = new DsfRunnable() { + public void run() { + // If the current display job does not match up with "this", it means that this job got cancelled + // after it already completed and after this runnable was queued into the dispatch thread. + if (fRunningDisplayJob == DisplayJob.this) { + fRunningDisplayJob = null; + serviceDisplayAndClearingJobs(); + } + } + }; + + if (monitor.isCanceled()) { + executeFromJob(displayJobFinishedRunnable); + return Status.CANCEL_STATUS; + } + + IEditorPart editor = openEditor(fResult, fPage); + if (editor == null) { + executeFromJob(displayJobFinishedRunnable); + return Status.OK_STATUS; + } + + ITextEditor textEditor = null; + if (editor instanceof ITextEditor) { + textEditor = (ITextEditor)editor; + } else { + textEditor = (ITextEditor) editor.getAdapter(ITextEditor.class); + } + if (textEditor != null) { + positionEditor(textEditor, fResult.getDmc()); + } + + executeFromJob(displayJobFinishedRunnable); + + return Status.OK_STATUS; + } + + /** + * Opens the editor used to display the source for an element selected in + * this view and returns the editor that was opened or null if + * no editor could be opened. + */ + private IEditorPart openEditor(SourceLookupResult result, IWorkbenchPage page) { + IEditorInput input= result.getEditorInput(); + String id= result.getEditorId(); + if (input == null || id == null) { + return null; + } + + return openEditor(page, input, id); + } + + /** + * Opens an editor in the workbench and returns the editor that was opened + * or null if an error occurred while attempting to open the + * editor. + */ + private IEditorPart openEditor(final IWorkbenchPage page, final IEditorInput input, final String id) { + final IEditorPart[] editor = new IEditorPart[] {null}; + Runnable r = new Runnable() { + public void run() { + if (!page.getWorkbenchWindow().getWorkbench().isClosing()) { + try { + editor[0] = page.openEditor(input, id, false); + } catch (PartInitException e) {} + } + } + }; + BusyIndicator.showWhile(Display.getDefault(), r); + return editor[0]; + } + + /** + * Positions the text editor for the given stack frame + */ + private void positionEditor(ITextEditor editor, final IDMContext dmc) { + if (!(dmc instanceof IFrameDMContext)) return; + final IFrameDMContext frameDmc = (IFrameDMContext)dmc; + + // We need to retrieve the frame level and line number from the service. + // Normally we could just get the needed information from IFrameDMData, but + // IFrameDMData, which derives from IModelData can only be accessed on the + // dispatch thread, so we need to copy over relevant information from + // IFrameDMData into this structure so we can read it in the job thread. + class FramePositioningData { + int fLine; + int fLevel; + } + + // Query the service for frame data. We are calling from a job thread, + // so we use the Query.get() method, which will block until the + // query is completed. + Query query = new Query(fExecutor) { + @Override + protected void execute(final DataRequestMonitor rm) { + IStack stackService = fServicesTracker.getService(IStack.class); + if (stackService == null) { + doneException(new CoreException(new Status(IStatus.ERROR, DsfDebugUIPlugin.PLUGIN_ID, -1, "Stack data not available", null))); //$NON-NLS-1$ + return; + } + stackService.getModelData( + frameDmc, + new DataRequestMonitor(fExecutor, rm) { + @Override + public void handleOK() { + FramePositioningData clientData = new FramePositioningData(); + clientData.fLevel = getData().getLevel(); + // Document line numbers are 0-based. While debugger line numbers are 1-based. + clientData.fLine = getData().getLine() - 1; + rm.setData(clientData); + rm.done(); + } + }); + } + }; + try { + fExecutor.execute(query); + FramePositioningData framePositioningData = query.get(); + // If the frame data is not available, or the line number is not + // known, give up. + if (framePositioningData == null || framePositioningData.fLevel < 0) { + return; + } + + // Position and annotate the editor. + IRegion region= getLineInformation(editor, framePositioningData.fLine); + if (region != null) { + editor.selectAndReveal(region.getOffset(), 0); + fIPManager.addAnnotation( + editor, frameDmc, new Position(region.getOffset(), region.getLength()), + framePositioningData.fLevel == 0); + } + } catch (InterruptedException e) { assert false : "Interrupted exception in DSF thread"; //$NON-NLS-1$ + } catch (ExecutionException e) { // Ignore + } + + + } + + /** + * Returns the line information for the given line in the given editor + */ + private IRegion getLineInformation(ITextEditor editor, int lineNumber) { + IDocumentProvider provider= editor.getDocumentProvider(); + IEditorInput input= editor.getEditorInput(); + try { + provider.connect(input); + } catch (CoreException e) { + return null; + } + try { + IDocument document= provider.getDocument(input); + if (document != null) + return document.getLineInformation(lineNumber); + } catch (BadLocationException e) { + } finally { + provider.disconnect(input); + } + return null; + } + + } + + /** + * Job that removes the old IP Annotations associated with given execution + * context. + */ + class ClearingJob extends UIJob { + List fDmcsToClear; + + public ClearingJob(List dmcs) { + super("Debug Source Display"); //$NON-NLS-1$ + setSystem(true); + setPriority(Job.INTERACTIVE); + fDmcsToClear = dmcs; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + DsfRunnable clearingJobFinishedRunnable = new DsfRunnable() { public void run() { + assert fRunningClearingJob == ClearingJob.this; + fRunningClearingJob = null; + serviceDisplayAndClearingJobs(); + }}; + + if (monitor.isCanceled()) { + executeFromJob(clearingJobFinishedRunnable); + return Status.CANCEL_STATUS; + } + + for (IRunControl.IExecutionDMContext dmc : fDmcsToClear) { + fIPManager.removeAnnotations(dmc); + } + + executeFromJob(clearingJobFinishedRunnable); + return Status.OK_STATUS; + } + } + + private DsfSession fSession; + private DsfExecutor fExecutor; + private DsfServicesTracker fServicesTracker; + private IDMContext fPrevModelContext; + private SourceLookupResult fPrevResult; + private ISourceLookupDirector fSourceLookup; + private DsfMISourceLookupParticipant fSourceLookupParticipant; + private InstructionPointerManager fIPManager; + + private LookupJob fRunningLookupJob; + private DisplayJob fRunningDisplayJob; + private DisplayJob fPendingDisplayJob; + private ClearingJob fRunningClearingJob; + private List fPendingExecDmcsToClear = new LinkedList(); + + public MISourceDisplayAdapter(DsfSession session, ISourceLookupDirector sourceLocator) { + fSession = session; + fExecutor = session.getExecutor(); + fServicesTracker = new DsfServicesTracker(DsfDebugUIPlugin.getBundleContext(), session.getId()); + fSourceLookup = sourceLocator; + fSourceLookupParticipant = new DsfMISourceLookupParticipant(session); + fSourceLookup.addParticipants(new ISourceLookupParticipant[] {fSourceLookupParticipant} ); + + fIPManager = new InstructionPointerManager(); + + fSession.addServiceEventListener(this, null); + } + + public void dispose() { + fSession.removeServiceEventListener(this); + fServicesTracker.dispose(); + fSourceLookup.removeParticipants(new ISourceLookupParticipant[] {fSourceLookupParticipant}); + + // fSourceLookupParticipant is disposed by teh source lookup director + + // Need to remove annotations in UI thread. + //fIPManager.removeAllAnnotations(); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.ui.contexts.ISourceDisplayAdapter#displaySource(java.lang.Object, org.eclipse.ui.IWorkbenchPage, boolean) + */ + public void displaySource(Object context, final IWorkbenchPage page, final boolean force) { + if (!(context instanceof DMVMContext)) return; + // Correct cast: (AbstractDMVMLayoutNode.DMVMContext) breaks the javac compiler + @SuppressWarnings("unchecked") + final IDMContext dmc = ((DMVMContext)context).getDMC(); + + // Quick test. DMC is checked again in source lookup participant, but + // it's much quicker to test here. + if (!(dmc instanceof IFrameDMContext)) return; + + // Re-dispatch to executor thread before accessing job lists. + fExecutor.execute(new DsfRunnable() { public void run() { + if (!force && dmc.equals(fPrevModelContext)) { + fPrevResult.updateArtifact(dmc); + startDisplayJob(fPrevResult, page); + } else { + startLookupJob(dmc, page); + } + }}); + } + + private void executeFromJob(Runnable runnable) { + try { + fExecutor.execute(runnable); + } catch (RejectedExecutionException e) { + // Session disposed, ignore + } + } + + private void startLookupJob(final IDMContext dmc, final IWorkbenchPage page) { + // If there is a previous lookup job running, cancel it. + if (fRunningLookupJob != null) { + fRunningLookupJob.cancel(); + } + + fRunningLookupJob = new LookupJob(dmc, page); + fRunningLookupJob.schedule(); + } + + // To be called only on dispatch thread. + private void startDisplayJob(SourceLookupResult lookupResult, IWorkbenchPage page) { + DisplayJob nextDisplayJob = new DisplayJob(lookupResult, page); + if (fRunningDisplayJob != null) { + // There is a display job currently running. Cancel it, and set + // the next display job to be run. + if (false && fRunningDisplayJob.cancel()) { + fPendingDisplayJob = nextDisplayJob; + fRunningDisplayJob = null; + serviceDisplayAndClearingJobs(); + } else { + // The job already started, so we need to wait until + // serviceDisplayAndClearingJobs() is called by the job itself. + fPendingDisplayJob = nextDisplayJob; + } + } else if (fRunningClearingJob != null) { + // Wait for the clearing job to finish, instead, set the + // display job as pending. + fPendingDisplayJob = nextDisplayJob; + } else { + fRunningDisplayJob = nextDisplayJob; + fRunningDisplayJob.schedule(); + } + } + + + private void serviceDisplayAndClearingJobs() { + if (!fPendingExecDmcsToClear.isEmpty()) { + // There are annotations to be cleared, run the job first + fRunningClearingJob = new ClearingJob(fPendingExecDmcsToClear); + fRunningClearingJob.schedule(); + fPendingExecDmcsToClear = new LinkedList(); + } else if (fPendingDisplayJob != null) { + fRunningDisplayJob = fPendingDisplayJob; + fRunningDisplayJob.schedule(); + fPendingDisplayJob = null; + } + } + + private void startAnnotationClearingJob(IRunControl.IExecutionDMContext execDmc) { + // Make sure to add the dmc to the list. + fPendingExecDmcsToClear.add(execDmc); + + // If lookup job is running, check it agains the exec context, + // and cancel it if matches. + if (fRunningLookupJob != null) { + if (DMContexts.isAncestorOf(fRunningLookupJob.getDmc(), execDmc)) { + fRunningLookupJob.cancel(); + fRunningLookupJob = null; + } + } + // If there is a pending displahy job, make sure it doesn't get + // pre-empted by this event. If so, just cancel the pending + // display job. + if (fPendingDisplayJob != null) { + if (DMContexts.isAncestorOf(fPendingDisplayJob.getDmc(), execDmc)) { + fPendingDisplayJob = null; + } + } + + // If no display or clearing jobs are running, schedule the clearing job. + if (fRunningClearingJob == null && fRunningDisplayJob == null) { + fRunningClearingJob = new ClearingJob(fPendingExecDmcsToClear); + fRunningClearingJob.schedule(); + fPendingExecDmcsToClear = new LinkedList(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.IResumedDMEvent e) { + if (e.getReason() != StateChangeReason.STEP) { + startAnnotationClearingJob(e.getDMContext()); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.IExitedDMEvent e) { + startAnnotationClearingJob(e.getExecutionContext()); + } + + @DsfServiceEventHandler + public void eventDispatched(IStepQueueManager.ISteppingTimedOutEvent e) { + startAnnotationClearingJob(e.getDMContext()); + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/SourceLookupResult.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/SourceLookupResult.java new file mode 100644 index 00000000000..fdf90a4eeab --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/ui/sourcelookup/SourceLookupResult.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.ui.sourcelookup; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.ui.IEditorInput; + +/** + * The result of a source lookup contains the source element, editor id, and + * editor input resolved for a debug artifact. + * + * @since 3.1 + */ +class SourceLookupResult { + + /** + * Element that source was resolved for. + */ + private IDMContext fDmc; + /** + * Corresponding source element, or null + * if unknown. + */ + private Object fSourceElement; + /** + * Associated editor id, used to display the source element, + * or null if unknown. + */ + private String fEditorId; + /** + * Associatd editor input, used to display the source element, + * or null if unknown. + */ + private IEditorInput fEditorInput; + + /** + * Creates a source lookup result on the given artifact, source element, + * editor id, and editor input. + */ + public SourceLookupResult(IDMContext dmc, Object sourceElement, String editorId, IEditorInput editorInput) { + fDmc = dmc; + setSourceElement(sourceElement); + setEditorId(editorId); + setEditorInput(editorInput); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.ui.sourcelookup.ISourceLookupResult#getArtifact() + */ + public IDMContext getDmc() { + return fDmc; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.ui.sourcelookup.ISourceLookupResult#getSourceElement() + */ + public Object getSourceElement() { + return fSourceElement; + } + + /** + * Sets the source element resolved for the artifact that source + * lookup was performed for, or null if a source element + * was not resolved. + * + * @param element resolved source element or null if unknown + */ + protected void setSourceElement(Object element) { + fSourceElement = element; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.ui.sourcelookup.ISourceLookupResult#getEditorId() + */ + public String getEditorId() { + return fEditorId; + } + + /** + * Sets the identifier of the editor used to display this source + * lookup result's source element, or null if unknown. + * + * @param id the identifier of the editor used to display this source + * lookup result's source element, or null if unknown + */ + protected void setEditorId(String id) { + fEditorId = id; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.ui.sourcelookup.ISourceLookupResult#getEditorInput() + */ + public IEditorInput getEditorInput() { + return fEditorInput; + } + + /** + * Sets the editor input used to display this source lookup + * result's source element, or null if unknown. + * + * @param input the editor input used to display this source lookup + * result's source element, or null if unknown + */ + protected void setEditorInput(IEditorInput input) { + fEditorInput = input; + } + + /** + * Updates the artifact to refer to the given artifact + * if equal. For example, when a source lookup result is resued + * for the same stack frame, we still need to update in case + * the stack frame is not identical. + * + * @param artifact new artifact state + */ + public void updateArtifact(IDMContext dmc) { + if (fDmc.equals(dmc)) { + fDmc = dmc; + } + } +} diff --git a/plugins/org.eclipse.dd.dsf.debug/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.dsf.debug/META-INF/MANIFEST.MF index e803dac64a4..42715ebf451 100644 --- a/plugins/org.eclipse.dd.dsf.debug/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.dd.dsf.debug/META-INF/MANIFEST.MF @@ -11,6 +11,8 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.dd.dsf, org.eclipse.cdt.core Eclipse-LazyStart: true -Export-Package: org.eclipse.dd.dsf.debug.service, - org.eclipse.dd.dsf.debug.service.command +Export-Package: org.eclipse.dd.dsf.debug.model, + org.eclipse.dd.dsf.debug.service, + org.eclipse.dd.dsf.debug.service.command, + org.eclipse.dd.dsf.debug.sourcelookup Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java new file mode 100644 index 00000000000..ffd9d525696 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.model; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.DsfDebugPlugin; +import org.eclipse.dd.dsf.debug.service.IMemory; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IMemoryBlockRetrieval; +import org.osgi.util.tracker.ServiceTracker; + +/** + * + */ +public class DsfMemoryBlockRetrieval implements IMemoryBlockRetrieval { + + private final IDMContext fContext; + private final ServiceTracker fServiceTracker; + + public DsfMemoryBlockRetrieval(IDMContext dmc) { + fContext = dmc; + String memoryServiceFilter = + "(&" + + "(OBJECTCLASS=" + IMemory.class.getName() + ")" + + "(" + IDsfService.PROP_SESSION_ID + "=" + dmc.getSessionId() + ")" + + ")"; + fServiceTracker = new ServiceTracker(DsfDebugPlugin.getBundleContext(), memoryServiceFilter, null); + fServiceTracker.open(); + } + + public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { + return null; + } + + public boolean supportsStorageRetrieval() { + return false; + } + +} diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/sourcelookup/DsfMISourceLookupParticipant.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/sourcelookup/DsfMISourceLookupParticipant.java new file mode 100644 index 00000000000..e890d519889 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/sourcelookup/DsfMISourceLookupParticipant.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.dsf.debug.sourcelookup; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.DsfDebugPlugin; +import org.eclipse.dd.dsf.debug.service.IStack; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMData; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.sourcelookup.ISourceContainer; +import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; +import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant; + +/** + */ +@ThreadSafe +public class DsfMISourceLookupParticipant implements ISourceLookupParticipant { + protected static final Object[] EMPTY = new Object[0]; + + private DsfExecutor fExecutor; + private String fSessionId; + private DsfServicesTracker fServicesTracker; + private ISourceLookupDirector fDirector; + private Map> fLookupCache = Collections.synchronizedMap(new HashMap>()); + + public DsfMISourceLookupParticipant(DsfSession session) { + fSessionId = session.getId(); + fExecutor = DsfSession.getSession(fSessionId).getExecutor(); + fServicesTracker = new DsfServicesTracker(DsfDebugPlugin.getBundleContext(), fSessionId); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#init(org.eclipse.debug.core.sourcelookup.ISourceLookupDirector) + */ + public void init(ISourceLookupDirector director) { + fDirector = director; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#dispose() + */ + public void dispose() { + fServicesTracker.dispose(); + fDirector = null; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#findSourceElements(java.lang.Object) + */ + public Object[] findSourceElements(Object object) throws CoreException { + CoreException single = null; + MultiStatus multiStatus = null; + List results = null; + + String name = getSourceName(object); + if (name != null) { + results = fLookupCache.get(name); + if (results != null) { + return results.toArray(); + } else { + results = new ArrayList(); + } + ISourceContainer[] containers = getSourceContainers(); + for (int i = 0; i < containers.length; i++) { + try { + ISourceContainer container = containers[i]; + if (container != null) { + Object[] objects = container.findSourceElements(name); + if (objects.length > 0) { + if (isFindDuplicates()) { + results.addAll(Arrays.asList(objects)); + } else { + results.add(objects[0]); + break; + } + } + } + } catch (CoreException e) { + if (single == null) { + single = e; + } else if (multiStatus == null) { + multiStatus = new MultiStatus(DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, new IStatus[]{single.getStatus()}, "Source Lookup error", null); //$NON-NLS-1$ + multiStatus.add(e.getStatus()); + } else { + multiStatus.add(e.getStatus()); + } + } + } + + if (!results.isEmpty()) { + synchronized(fLookupCache) { + if (!fLookupCache.containsKey(name)) { + fLookupCache.put(name, results); + } + } + } + } + if (results == null || results.isEmpty()) { + if (multiStatus != null) { + throw new CoreException(multiStatus); + } else if (single != null) { + throw single; + } + return EMPTY; + } + return results.toArray(); + } + + /** + * Returns whether this participant's source lookup director is configured + * to search for duplicate source elements. + * + * @return whether this participant's source lookup director is configured + * to search for duplicate source elements + */ + protected boolean isFindDuplicates() { + ISourceLookupDirector director = fDirector; + if (director != null) { + return director.isFindDuplicates(); + } + return false; + } + + /** + * Returns the source containers currently registered with this participant's + * source lookup director. + * + * @return the source containers currently registered with this participant's + * source lookup director + */ + protected ISourceContainer[] getSourceContainers() { + ISourceLookupDirector director = fDirector; + if (director != null) { + return director.getSourceContainers(); + } + return new ISourceContainer[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#sourceContainersChanged(org.eclipse.debug.core.sourcelookup.ISourceLookupDirector) + */ + public void sourceContainersChanged(ISourceLookupDirector director) { + fLookupCache.clear(); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.internal.core.sourcelookup.ISourceLookupParticipant#getSourceName(java.lang.Object) + */ + public String getSourceName(Object object) throws CoreException { + if ( !(object instanceof IDMContext) || + !((IDMContext)object).getSessionId().equals(fSessionId) ) + { + throw new CoreException(new Status(IStatus.ERROR, DsfDebugPlugin.PLUGIN_ID, -1, "Invalid object", null)); //$NON-NLS-1$ + } + + final IDMContext dmc = (IDMContext)object; + Query query = new Query(fExecutor) { + @Override + protected void execute(final DataRequestMonitor rm) { + getSourceNameOnDispatchThread(dmc, rm); + }}; + fExecutor.execute(query); + try { + return query.get(); + } catch (InterruptedException e) { assert false : "Interrupted exception in DSF executor"; //$NON-NLS-1$ + } catch (ExecutionException e) { + if (e.getCause() instanceof CoreException) { + throw (CoreException)e.getCause(); + } + assert false : "Unexptected exception"; //$NON-NLS-1$ + } + return null; // Should never get here. + } + + @ConfinedToDsfExecutor("fExecutor") + private void getSourceNameOnDispatchThread(IDMContext dmc, final DataRequestMonitor rm) { + if (!(dmc instanceof IStack.IFrameDMContext)) { + rm.setStatus(new Status(IStatus.ERROR, DsfDebugPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "No source for this object", null)); //$NON-NLS-1$ + rm.done(); + return; + } + IFrameDMContext frameDmc = (IFrameDMContext)dmc; + + IStack stackService = fServicesTracker.getService(IStack.class); + if (stackService == null) { + rm.setStatus(new Status(IStatus.ERROR, DsfDebugPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Stack data not available", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + stackService.getModelData( + frameDmc, + new DataRequestMonitor(fExecutor, rm) { @Override + public void handleOK() { + rm.setData(getData().getFile()); + rm.done(); + }}); + } +}