diff options
Diffstat (limited to 'plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf')
34 files changed, 6317 insertions, 0 deletions
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java new file mode 100644 index 000000000..5ce3dbb2b --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleListener; + +import com.windriver.debug.tcf.ui.model.TCFModelManager; + +/** + * The activator class controls the plug-in life cycle + */ +public class TCFUI extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "com.windriver.debug.tcf.ui"; + + // The shared instance + private static TCFUI plugin; + private static TCFModelManager model_manager; + + private static final BundleListener bundle_listener = new BundleListener() { + public void bundleChanged(BundleEvent event) { + if (plugin != null && event.getBundle() == plugin.getBundle() && + plugin.getBundle().getState() != Bundle.ACTIVE && model_manager != null) { + model_manager.dispose(); + model_manager = null; + } + } + }; + + /** + * The constructor + */ + public TCFUI() { + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + context.addBundleListener(bundle_listener); + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static TCFUI getDefault() { + return plugin; + } + + /** + * Returns the shared TCFModel instance + * + * @return the shared TCFModel instance + */ + public static TCFModelManager getModelManager() { + if (plugin != null && model_manager == null && plugin.getBundle().getState() == Bundle.ACTIVE) { + model_manager = new TCFModelManager(); + } + return model_manager; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java new file mode 100644 index 000000000..c5f428dac --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.adapters; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget; +import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension; + +import com.windriver.debug.tcf.ui.commands.BreakpointCommand; +import com.windriver.debug.tcf.ui.model.TCFNode; + +public class TCFBreakpointAdapterFactory implements IAdapterFactory { + + @SuppressWarnings("unchecked") + public Object getAdapter(Object obj, Class adapterType) { + if (obj instanceof TCFNode) { + return new BreakpointCommand(); + } + System.out.println(obj.getClass().getName() + " -> " + adapterType); + return null; + } + + @SuppressWarnings("unchecked") + public Class[] getAdapterList() { + return new Class[]{ IToggleBreakpointsTarget.class, IToggleBreakpointsTargetExtension.class }; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java new file mode 100644 index 000000000..4159fcea4 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.adapters; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.debug.core.commands.ITerminateHandler; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; + +import com.windriver.debug.tcf.core.model.TCFLaunch; +import com.windriver.debug.tcf.ui.TCFUI; +import com.windriver.debug.tcf.ui.model.TCFModel; +import com.windriver.tcf.api.protocol.Protocol; + +public class TCFLaunchAdapterFactory implements IAdapterFactory { + + @SuppressWarnings("unchecked") + private final Class[] adapter_list = { + IElementContentProvider.class, + IElementLabelProvider.class, + IModelProxyFactory.class, + ITerminateHandler.class + }; + + @SuppressWarnings("unchecked") + public Object getAdapter(final Object from, final Class to) { + if (from instanceof TCFLaunch) { + final Object[] res = new Object[1]; + Protocol.invokeAndWait(new Runnable() { + public void run() { + TCFLaunch launch = (TCFLaunch)from; + TCFModel model = TCFUI.getModelManager().getModel(launch); + if (model != null) { + if (to.isInstance(model)) { + res[0] = model; + return; + } + Object cmd = model.getCommand(to); + if (cmd != null) { + res[0] = cmd; + return; + } + } + } + }); + if (res[0] != null) return res[0]; + } + System.err.println(from.getClass().getName() + " -> " + to); + return null; + } + + @SuppressWarnings("unchecked") + public Class[] getAdapterList() { + return adapter_list; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java new file mode 100644 index 000000000..d8ad27b10 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.adapters; + +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; + +public class TCFModelSelectionPolicyFactoryAdapter implements IModelSelectionPolicyFactory { + + public IModelSelectionPolicy createModelSelectionPolicyAdapter( + Object element, IPresentationContext context) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java new file mode 100644 index 000000000..12ec02760 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.commands; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IWorkbenchPart; + +import com.windriver.debug.tcf.core.model.TCFBreakpoint; +import com.windriver.debug.tcf.ui.model.TCFNode; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.services.IBreakpoints; + +public class BreakpointCommand implements IToggleBreakpointsTargetExtension { + + public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) { + Object obj = ((IStructuredSelection)selection).getFirstElement(); + if (obj instanceof TCFNode) { + final TCFNode node = (TCFNode)obj; + if (node == null) return false; + final boolean[] res = new boolean[1]; + Protocol.invokeAndWait(new Runnable() { + public void run() { + res[0] = node.getAddress() != null; + } + }); + return res[0]; + } + else { + return false; + } + } + + public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { + Object obj = ((IStructuredSelection)selection).getFirstElement(); + if (obj instanceof TCFNode) { + final TCFNode node = (TCFNode)obj; + if (node == null) return; + final CoreException[] res = new CoreException[1]; + Protocol.invokeAndWait(new Runnable() { + public void run() { + try { + String addr = node.getAddress(); + if (addr == null) return; + Map<String,Object> m = new HashMap<String,Object>(); + m.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE); + m.put(IBreakpoints.PROP_ADDRESS, addr); + new TCFBreakpoint(ResourcesPlugin.getWorkspace().getRoot(), m); + } + catch (CoreException x) { + res[0] = x; + } + } + }); + if (res[0] != null) throw res[0]; + } + } + + public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) { + // TODO Auto-generated method stub + return false; + } + + public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { + // TODO Auto-generated method stub + + } + + public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) { + // TODO Auto-generated method stub + return false; + } + + public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { + // TODO Auto-generated method stub + + } + + public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) { + // TODO Auto-generated method stub + return false; + } + + public void toggleWatchpoints(IWorkbenchPart part, ISelection selection) throws CoreException { + // TODO Auto-generated method stub + + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java new file mode 100644 index 000000000..3ef011689 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.commands; + +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IDisconnectHandler; +import org.eclipse.debug.core.commands.IEnabledStateRequest; + +import com.windriver.debug.tcf.ui.model.TCFModel; +import com.windriver.debug.tcf.ui.model.TCFRunnable; + +public class DisconnectCommand implements IDisconnectHandler { + + private final TCFModel model; + + public DisconnectCommand(TCFModel model) { + this.model = model; + } + + public void canExecute(final IEnabledStateRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + monitor.setEnabled(model.getLaunch().canDisconnect()); + monitor.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + public boolean execute(final IDebugCommandRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + try { + model.getLaunch().disconnect(); + monitor.setStatus(Status.OK_STATUS); + } + catch (DebugException x) { + monitor.setStatus(x.getStatus()); + } + done(); + } + }; + return false; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java new file mode 100644 index 000000000..f4ecd5049 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.commands; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.IResumeHandler; + +import com.windriver.debug.tcf.ui.TCFUI; +import com.windriver.debug.tcf.ui.model.TCFModel; +import com.windriver.debug.tcf.ui.model.TCFNode; +import com.windriver.debug.tcf.ui.model.TCFRunnable; +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IRunControl; + +public class ResumeCommand implements IResumeHandler { + + private final TCFModel model; + + public ResumeCommand(TCFModel model) { + this.model = model; + } + + public void canExecute(final IEnabledStateRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + boolean res = false; + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null) { + node = node.getParent(); + } + else if (ctx.isContainer()) { + if (ctx.canResume(IRunControl.RM_RESUME)) res = true; + node = null; + } + else { + if (node.isSuspended() && ctx.canResume(IRunControl.RM_RESUME)) res = true; + node = null; + } + } + } + monitor.setEnabled(res); + monitor.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + public boolean execute(final IDebugCommandRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>(); + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null) { + node = node.getParent(); + } + else { + set.add(ctx); + node = null; + } + } + } + final Set<IToken> cmds = new HashSet<IToken>(); + for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) { + IRunControl.RunControlContext ctx = i.next(); + cmds.add(ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + assert cmds.contains(token); + cmds.remove(token); + if (error != null) { + monitor.setStatus(new Status(IStatus.ERROR, + TCFUI.PLUGIN_ID, IStatus.OK, "Cannot resume", error)); + } + if (cmds.isEmpty()) done(); + } + })); + } + } + }; + return true; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java new file mode 100644 index 000000000..76e09d274 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.commands; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.IStepIntoHandler; + +import com.windriver.debug.tcf.ui.TCFUI; +import com.windriver.debug.tcf.ui.model.TCFModel; +import com.windriver.debug.tcf.ui.model.TCFNode; +import com.windriver.debug.tcf.ui.model.TCFRunnable; +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IRunControl; + +public class StepIntoCommand implements IStepIntoHandler { + + private final TCFModel model; + + public StepIntoCommand(TCFModel model) { + this.model = model; + } + + public void canExecute(final IEnabledStateRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + boolean res = false; + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_INTO)) { + node = node.getParent(); + } + else { + if (node.isSuspended()) res = true; + node = null; + } + } + } + monitor.setEnabled(res); + monitor.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + public boolean execute(final IDebugCommandRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>(); + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_INTO)) { + node = node.getParent(); + } + else { + set.add(ctx); + node = null; + } + } + } + final Set<IToken> cmds = new HashSet<IToken>(); + for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) { + IRunControl.RunControlContext ctx = i.next(); + cmds.add(ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + assert cmds.contains(token); + cmds.remove(token); + if (error != null) { + monitor.setStatus(new Status(IStatus.ERROR, + TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error)); + } + if (cmds.isEmpty()) done(); + } + })); + } + } + }; + return true; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java new file mode 100644 index 000000000..3a8170fbb --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.commands; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.IStepOverHandler; + +import com.windriver.debug.tcf.ui.TCFUI; +import com.windriver.debug.tcf.ui.model.TCFModel; +import com.windriver.debug.tcf.ui.model.TCFNode; +import com.windriver.debug.tcf.ui.model.TCFRunnable; +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IRunControl; + +public class StepOverCommand implements IStepOverHandler { + + private final TCFModel model; + + public StepOverCommand(TCFModel model) { + this.model = model; + } + + public void canExecute(final IEnabledStateRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + boolean res = false; + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OVER)) { + node = node.getParent(); + } + else { + if (node.isSuspended()) res = true; + node = null; + } + } + } + monitor.setEnabled(res); + monitor.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + public boolean execute(final IDebugCommandRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>(); + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OVER)) { + node = node.getParent(); + } + else { + set.add(ctx); + node = null; + } + } + } + final Set<IToken> cmds = new HashSet<IToken>(); + for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) { + IRunControl.RunControlContext ctx = i.next(); + cmds.add(ctx.resume(IRunControl.RM_STEP_OVER, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + assert cmds.contains(token); + cmds.remove(token); + if (error != null) { + monitor.setStatus(new Status(IStatus.ERROR, + TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error)); + } + if (cmds.isEmpty()) done(); + } + })); + } + } + }; + return true; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java new file mode 100644 index 000000000..8975a8155 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.commands; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.IStepReturnHandler; + +import com.windriver.debug.tcf.ui.TCFUI; +import com.windriver.debug.tcf.ui.model.TCFModel; +import com.windriver.debug.tcf.ui.model.TCFNode; +import com.windriver.debug.tcf.ui.model.TCFRunnable; +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IRunControl; + +public class StepReturnCommand implements IStepReturnHandler { + + private final TCFModel model; + + public StepReturnCommand(TCFModel model) { + this.model = model; + } + + public void canExecute(final IEnabledStateRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + boolean res = false; + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OUT)) { + node = node.getParent(); + } + else { + if (node.isSuspended()) res = true; + node = null; + } + } + } + monitor.setEnabled(res); + monitor.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + public boolean execute(final IDebugCommandRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>(); + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OUT)) { + node = node.getParent(); + } + else { + set.add(ctx); + node = null; + } + } + } + final Set<IToken> cmds = new HashSet<IToken>(); + for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) { + IRunControl.RunControlContext ctx = i.next(); + cmds.add(ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + assert cmds.contains(token); + cmds.remove(token); + if (error != null) { + monitor.setStatus(new Status(IStatus.ERROR, + TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error)); + } + if (cmds.isEmpty()) done(); + } + })); + } + } + }; + return true; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java new file mode 100644 index 000000000..45419650e --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.commands; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.ISuspendHandler; + +import com.windriver.debug.tcf.ui.TCFUI; +import com.windriver.debug.tcf.ui.model.TCFModel; +import com.windriver.debug.tcf.ui.model.TCFNode; +import com.windriver.debug.tcf.ui.model.TCFRunnable; +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IRunControl; + +public class SuspendCommand implements ISuspendHandler { + + private final TCFModel model; + + public SuspendCommand(TCFModel model) { + this.model = model; + } + + public void canExecute(final IEnabledStateRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + boolean res = false; + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null) { + node = node.getParent(); + } + else if (ctx.isContainer()) { + if (ctx.canSuspend()) res = true; + node = null; + } + else { + if (node.isRunning() && ctx.canSuspend()) res = true; + node = null; + } + } + } + monitor.setEnabled(res); + monitor.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + public boolean execute(final IDebugCommandRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>(); + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx == null) { + node = node.getParent(); + } + else { + set.add(ctx); + node = null; + } + } + } + final Set<IToken> cmds = new HashSet<IToken>(); + for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) { + IRunControl.RunControlContext ctx = i.next(); + cmds.add(ctx.suspend(new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + assert cmds.contains(token); + cmds.remove(token); + if (error != null) { + monitor.setStatus(new Status(IStatus.ERROR, + TCFUI.PLUGIN_ID, IStatus.OK, "Cannot suspend", error)); + } + if (cmds.isEmpty()) done(); + } + })); + } + } + }; + return true; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java new file mode 100644 index 000000000..81f16e12a --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.commands; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.ITerminateHandler; + +import com.windriver.debug.tcf.ui.TCFUI; +import com.windriver.debug.tcf.ui.model.TCFModel; +import com.windriver.debug.tcf.ui.model.TCFNode; +import com.windriver.debug.tcf.ui.model.TCFRunnable; +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IRunControl; + +public class TerminateCommand implements ITerminateHandler { + + private final TCFModel model; + + public TerminateCommand(TCFModel model) { + this.model = model; + } + + public void canExecute(final IEnabledStateRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + boolean res = false; + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx != null && ctx.canTerminate()) { + res = true; + node = null; + } + else { + node = node.getParent(); + if (node == null && model.getLaunch().canTerminate()) res = true; + } + } + } + monitor.setEnabled(res); + monitor.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + public boolean execute(final IDebugCommandRequest monitor) { + new TCFRunnable(model.getDisplay(), monitor) { + public void run() { + Object[] elements = monitor.getElements(); + Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>(); + for (int i = 0; i < elements.length; i++) { + TCFNode node = null; + if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; + else node = model.getRootNode(); + while (node != null && !node.isDisposed()) { + if (!node.validateNode(this)) return; + IRunControl.RunControlContext ctx = node.getRunContext(); + if (ctx != null && ctx.canTerminate()) { + set.add(ctx); + node = null; + } + else { + node = node.getParent(); + if (node == null) set.add(null); + } + } + } + final Set<IToken> cmds = new HashSet<IToken>(); + for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) { + IRunControl.RunControlContext ctx = i.next(); + if (ctx == null) { + cmds.add(null); + model.getLaunch().terminate(new Runnable() { + public void run() { + assert cmds.contains(null); + cmds.remove(null); + if (cmds.isEmpty()) done(); + } + }); + } + else { + cmds.add(ctx.terminate(new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + assert cmds.contains(token); + cmds.remove(token); + if (error != null) { + monitor.setStatus(new Status(IStatus.ERROR, + TCFUI.PLUGIN_ID, IStatus.OK, "Cannot resume", error)); + } + if (cmds.isEmpty()) done(); + } + })); + } + } + } + }; + return false; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java new file mode 100644 index 000000000..082d741bc --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.launch; + +import java.net.URL; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.debug.ui.StringVariableSelectionDialog; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Text; + +import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate; +import com.windriver.debug.tcf.ui.TCFUI; + +public class TCFArgumentsTab extends AbstractLaunchConfigurationTab { + + private Text text_arguments; + private Button button_variables; + private Text text_working_dir; + private Button button_default_dir; + private Image image; + + public void createControl(Composite parent) { + Font font = parent.getFont(); + Composite comp = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(1, true); + comp.setLayout(layout); + comp.setFont(font); + + GridData gd = new GridData(GridData.FILL_BOTH); + comp.setLayoutData(gd); + setControl(comp); + + createArgumentsGroup(comp); + createWorkingDirGroup(comp); + + URL url = FileLocator.find(TCFUI.getDefault().getBundle(), + new Path("icons/arguments_tab.gif"), null); + ImageDescriptor descriptor = null; + if (url == null) { + descriptor = ImageDescriptor.getMissingImageDescriptor(); + } + else { + descriptor = ImageDescriptor.createFromURL(url); + } + image = descriptor.createImage(parent.getDisplay()); + } + + private void createArgumentsGroup(Composite comp) { + Font font = comp.getFont(); + + Group group = new Group(comp, SWT.NONE); + group.setFont(font); + group.setLayout(new GridLayout()); + group.setLayoutData(new GridData(GridData.FILL_BOTH)); + group.setText("Program Arguments"); + + text_arguments = new Text(group, SWT.MULTI | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL); + GridData gd = new GridData(GridData.FILL_BOTH); + gd.heightHint = 40; + gd.widthHint = 100; + text_arguments.setLayoutData(gd); + text_arguments.setFont(font); + text_arguments.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent evt) { + updateLaunchConfigurationDialog(); + } + }); + button_variables= createPushButton(group, "Variables", null); + gd = new GridData(GridData.HORIZONTAL_ALIGN_END); + button_variables.setLayoutData(gd); + button_variables.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent arg0) { + handleVariablesButtonSelected(text_arguments); + } + }); + } + + private void createWorkingDirGroup(Composite comp) { + Font font = comp.getFont(); + + Group group = new Group(comp, SWT.NONE); + GridLayout workingDirLayout = new GridLayout(); + workingDirLayout.makeColumnsEqualWidth = false; + group.setLayout(workingDirLayout); + group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + group.setFont(font); + group.setText("Working directory"); + + text_working_dir = new Text(group, SWT.SINGLE | SWT.BORDER); + text_working_dir.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + text_working_dir.setFont(font); + + button_default_dir = new Button(group, SWT.CHECK); + button_default_dir.setText("Use default"); + button_default_dir.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false)); + button_default_dir.setFont(font); + } + + @Override + public void dispose() { + if (image != null) { + image.dispose(); + image = null; + } + super.dispose(); + } + + /** + * A variable entry button has been pressed for the given text + * field. Prompt the user for a variable and enter the result + * in the given field. + */ + private void handleVariablesButtonSelected(Text textField) { + String variable = getVariable(); + if (variable != null) textField.append(variable); + } + + /** + * Prompts the user to choose and configure a variable and returns + * the resulting string, suitable to be used as an attribute. + */ + private String getVariable() { + StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell()); + dialog.open(); + return dialog.getVariableExpression(); + } + + public boolean isValid(ILaunchConfiguration config) { + return true; + } + + public void setDefaults(ILaunchConfigurationWorkingCopy config) { + config.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, (String)null); + config.setAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, (String)null); + } + + public void initializeFrom(ILaunchConfiguration configuration) { + try { + text_arguments.setText(configuration.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, "")); //$NON-NLS-1$ + text_working_dir.setText(configuration.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, "")); //$NON-NLS-1$ + } + catch (CoreException e) { + setErrorMessage("Cannot read launch configuration: " + e); + } + } + + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + configuration.setAttribute( + TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, + getAttributeValueFrom(text_arguments)); + configuration.setAttribute( + TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, + getAttributeValueFrom(text_working_dir)); + } + + protected String getAttributeValueFrom(Text text) { + String content = text.getText().trim(); + content = content.replaceAll("\r\n", "\n"); // eliminate Windows \r line delimiter + if (content.length() > 0) return content; + return null; + } + + public String getName() { + return "Arguments"; + } + + @Override + public Image getImage() { + return image; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java new file mode 100644 index 000000000..3e9168d3c --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java @@ -0,0 +1,718 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.launch; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CLabel; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ProgressBar; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; + +import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate; +import com.windriver.debug.tcf.ui.TCFUI; +import com.windriver.tcf.api.protocol.IChannel; +import com.windriver.tcf.api.protocol.IPeer; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.services.ILocator; + +/** + * Launch configuration dialog tab to specify the Target Communication Framework + * configuration. + */ +public class TCFMainTab extends AbstractLaunchConfigurationTab { + + private Text peer_id_text; + private Text program_text; + private Tree peer_tree; + private PeerInfo[] peer_info; + private Display display; + + private final Map<LocatorListener,ILocator> listeners = new HashMap<LocatorListener,ILocator>(); + private final Map<String,Image> image_cache = new HashMap<String,Image>(); + + private static class PeerInfo { + PeerInfo parent; + int index; + PeerInfo[] children; + Map<String,String> attrs; + } + + private class LocatorListener implements ILocator.LocatorListener { + + private final PeerInfo parent; + + LocatorListener(PeerInfo parent) { + this.parent = parent; + } + + public void peerAdded(IPeer peer) { + if (display == null) return; + final Map<String,String> attrs = new HashMap<String,String>(peer.getAttributes()); + display.asyncExec(new Runnable() { + public void run() { + PeerInfo[] arr = parent == null ? peer_info : parent.children; + PeerInfo[] buf = new PeerInfo[arr.length + 1]; + System.arraycopy(arr, 0, buf, 0, arr.length); + PeerInfo info = new PeerInfo(); + info.parent = parent; + info.index = arr.length; + info.attrs = attrs; + buf[arr.length] = info; + if (parent == null) { + peer_info = buf; + } + else { + parent.children = buf; + } + updateItems(); + } + }); + } + + public void peerChanged(IPeer peer) { + if (display == null) return; + final Map<String,String> attrs = new HashMap<String,String>(peer.getAttributes()); + display.asyncExec(new Runnable() { + public void run() { + String id = attrs.get(IPeer.ATTR_ID); + PeerInfo[] arr = parent == null ? peer_info : parent.children; + for (int i = 0; i < arr.length; i++) { + if (arr[i].attrs.get(IPeer.ATTR_ID).equals(id)) { + arr[i].attrs = attrs; + updateItems(); + } + } + assert false; + } + }); + } + + public void peerRemoved(final String id) { + if (display == null) return; + display.asyncExec(new Runnable() { + public void run() { + PeerInfo[] arr = parent == null ? peer_info : parent.children; + PeerInfo[] buf = new PeerInfo[arr.length - 1]; + int j = 0; + for (int i = 0; i < arr.length; i++) { + if (!arr[i].attrs.get(IPeer.ATTR_ID).equals(id)) { + buf[j++] = arr[i]; + } + } + if (parent == null) { + peer_info = buf; + } + else { + parent.children = buf; + } + updateItems(); + } + }); + } + + private void updateItems() { + PeerInfo[] arr = null; + TreeItem[] items = null; + if (parent == null) { + arr = peer_info; + peer_tree.setItemCount(arr.length); + items = peer_tree.getItems(); + } + else { + TreeItem item = findItem(parent); + if (item == null) return; + arr = parent.children; + item.setItemCount(arr.length); + items = item.getItems(); + } + assert items.length == arr.length; + for (int i = 0; i < items.length; i++) { + fillItem(items[i], arr[i]); + } + String id = peer_id_text.getText(); + TreeItem item = findItem(findPeerInfo(id)); + if (item != null) peer_tree.setSelection(item); + } + } + + public void createControl(Composite parent) { + display = parent.getDisplay(); + + Font font = parent.getFont(); + Composite comp = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(1, true); + comp.setLayout(layout); + comp.setFont(font); + + GridData gd = new GridData(GridData.FILL_BOTH); + comp.setLayoutData(gd); + setControl(comp); + + createTargetGroup(comp); + createProgramGroup(comp); + } + + private void createTargetGroup(Composite parent) { + Font font = parent.getFont(); + + Group group = new Group(parent, SWT.NONE); + GridLayout top_layout = new GridLayout(); + top_layout.verticalSpacing = 0; + top_layout.numColumns = 2; + group.setLayout(top_layout); + group.setLayoutData(new GridData(GridData.FILL_BOTH)); + group.setFont(font); + group.setText("Target"); + + createVerticalSpacer(group, top_layout.numColumns); + + Label host_label = new Label(group, SWT.NONE); + host_label.setText("Target ID:"); + host_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + host_label.setFont(font); + + peer_id_text = new Text(group, SWT.SINGLE | SWT.BORDER); + peer_id_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + peer_id_text.setFont(font); + peer_id_text.setEditable(false); + peer_id_text.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + updateLaunchConfigurationDialog(); + } + }); + + createVerticalSpacer(group, top_layout.numColumns); + + Label peer_label = new Label(group, SWT.NONE); + peer_label.setText("Available targets:"); + peer_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + peer_label.setFont(font); + + if (peer_info == null) loadPeerInfo(null); + + peer_tree = new Tree(group, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE); + GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1); + gd.minimumHeight = 150; + peer_tree.setLayoutData(gd); + + for (int i = 0; i < 5; i++) { + TreeColumn column = new TreeColumn(peer_tree, SWT.LEAD, i); + column.setMoveable(true); + switch (i) { + case 0: + column.setText("Name"); + column.setWidth(120); + break; + case 1: + column.setText("OS"); + column.setWidth(100); + break; + case 2: + column.setText("Transport"); + column.setWidth(60); + break; + case 3: + column.setText("Host"); + column.setWidth(100); + break; + case 4: + column.setText("Port"); + column.setWidth(40); + break; + } + } + + peer_tree.setHeaderVisible(true); + peer_tree.setFont(font); + peer_tree.setItemCount(peer_info.length); + peer_tree.addListener(SWT.SetData, new Listener() { + public void handleEvent(Event event) { + TreeItem item = (TreeItem)event.item; + PeerInfo info = findPeerInfo(item); + fillItem(item, info); + } + }); + peer_tree.addSelectionListener(new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + } + public void widgetSelected(SelectionEvent e) { + TreeItem[] selections = peer_tree.getSelection(); + if (selections.length > 0) { + assert selections.length == 1; + PeerInfo info = findPeerInfo(selections[0]); + peer_id_text.setText(getPath(info)); + } + } + }); + + createVerticalSpacer(group, top_layout.numColumns); + + Button button_test = new Button(group, SWT.PUSH); + button_test.setText("Run &Diagnostics"); + button_test.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + button_test.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + TreeItem[] selection = peer_tree.getSelection(); + if (selection.length > 0) { + assert selection.length == 1; + runDiagnostics(selection[0], false); + } + } + }); + + Button button_loop = new Button(group, SWT.PUSH); + button_loop.setText("Diagnostics &Loop"); + button_loop.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING)); + button_loop.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + TreeItem[] selection = peer_tree.getSelection(); + if (selection.length > 0) { + assert selection.length == 1; + runDiagnostics(selection[0], true); + } + } + }); + } + + private void createProgramGroup(Composite parent) { + display = parent.getDisplay(); + + Font font = parent.getFont(); + + Group group = new Group(parent, SWT.NONE); + GridLayout top_layout = new GridLayout(); + group.setLayout(top_layout); + group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + group.setFont(font); + group.setText("Program"); + + program_text = new Text(group, SWT.SINGLE | SWT.BORDER); + program_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + program_text.setFont(font); + } + + @Override + public void dispose() { + Protocol.invokeAndWait(new Runnable() { + public void run() { + for (Iterator<LocatorListener> i = listeners.keySet().iterator(); i.hasNext();) { + LocatorListener listener = i.next(); + listeners.get(listener).removeListener(listener); + } + listeners.clear(); + peer_info = null; + display = null; + } + }); + for (Image i : image_cache.values()) i.dispose(); + image_cache.clear(); + super.dispose(); + } + + public String getName() { + return "Main"; + } + + @Override + public Image getImage() { + return getImage("icons/tcf.gif"); + } + + public void initializeFrom(ILaunchConfiguration configuration) { + try { + String id = configuration.getAttribute( + TCFLaunchDelegate.ATTR_PEER_ID, (String)null); + if (id != null) { + peer_id_text.setText(id); + TreeItem item = findItem(findPeerInfo(id)); + if (item != null) peer_tree.setSelection(item); + } + program_text.setText(configuration.getAttribute( + TCFLaunchDelegate.ATTR_PROGRAM_FILE, "")); //$NON-NLS-1$ + } + catch (CoreException e) { + setErrorMessage(e.getMessage()); + } + } + + public boolean isValid(ILaunchConfiguration launchConfig) { + String id = peer_id_text.getText().trim(); + if (id.length() == 0) { + setErrorMessage("Specify a target ID"); + return false; + } + setErrorMessage(null); + return super.isValid(launchConfig); + } + + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + String id = peer_id_text.getText().trim(); + if (id.length() == 0) id = null; + configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, id); + String nm = program_text.getText().trim(); + if (nm.length() == 0) nm = null; + configuration.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, nm); + } + + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, "TCFLocal"); + configuration.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, (String)null); + } + + private void loadPeerInfo(final PeerInfo parent) { + Protocol.invokeAndWait(new Runnable() { + public void run() { + if (parent == null) { + ILocator locator = Protocol.getLocator(); + Map<String,IPeer> map = locator.getPeers(); + PeerInfo[] buf = new PeerInfo[map.size()]; + int n = 0; + for (Iterator<IPeer> i = map.values().iterator(); i.hasNext();) { + IPeer p = i.next(); + PeerInfo info = new PeerInfo(); + info.parent = parent; + info.index = n; + info.attrs = new HashMap<String,String>(p.getAttributes()); + buf[n++] = info; + } + LocatorListener listener = new LocatorListener(parent); + listeners.put(listener, locator); + locator.addListener(listener); + assert peer_info == null; + peer_info = buf; + } + else { + PeerInfo[] buf = new PeerInfo[0]; + assert parent.children == null; + parent.children = buf; + } + } + }); + } + + private PeerInfo findPeerInfo(TreeItem item) { + TreeItem parent = item.getParentItem(); + if (parent == null) return peer_info[peer_tree.indexOf(item)]; + PeerInfo info = findPeerInfo(parent); + if (info.children == null) loadPeerInfo(info); + return info.children[parent.indexOf(item)]; + } + + private PeerInfo findPeerInfo(String path) { + int i = path.lastIndexOf('/'); + String id = null; + PeerInfo[] arr = null; + if (i < 0) { + if (peer_info == null) loadPeerInfo(null); + arr = peer_info; + id = path; + } + else { + PeerInfo p = findPeerInfo(path.substring(0, i)); + if (p == null) return null; + if (p.children == null) loadPeerInfo(p); + arr = p.children; + id = path.substring(i + 1); + } + for (int n = 0; n < arr.length; n++) { + if (arr[n].attrs.get(IPeer.ATTR_ID).equals(id)) return arr[n]; + } + return null; + } + + private TreeItem findItem(PeerInfo info) { + if (info == null) return null; + if (info.parent == null) { + return peer_tree.getItem(info.index); + } + TreeItem i = findItem(info.parent); + if (i == null) return null; + peer_tree.showItem(i); + return i.getItem(info.index); + } + + private interface DoneFindPeer { + void doneFindPeer(Collection<Throwable> errors, IPeer peer); + } + + private void findPeer(TreeItem item, final DoneFindPeer done) { + assert display != null; + assert Thread.currentThread() == display.getThread(); + final String path = getPath(findPeerInfo(item)); + Protocol.invokeLater(new Runnable() { + public void run() { + final Collection<Throwable> errors = new ArrayList<Throwable>(); + try { + final int i = path.lastIndexOf('/'); + if (i < 0) { + done.doneFindPeer(errors, Protocol.getLocator().getPeers().get(path)); + } + else { + openChannel(path.substring(0, i), errors, new DoneOpenChannel() { + public void doneOpenChannel(IChannel channel) { + IPeer peer = null; + if (channel != null) { + ILocator locator = channel.getRemoteService(ILocator.class); + peer = locator.getPeers().get(path.substring(i + 1)); + channel.close(); + } + done.doneFindPeer(errors, peer); + } + }); + } + } + catch (Throwable x) { + errors.add(x); + done.doneFindPeer(errors, null); + } + } + }); + } + + private interface DoneOpenChannel { + void doneOpenChannel(IChannel channel); + } + + private static class OpenChannelListener implements IChannel.IChannelListener { + + private final Collection<Throwable> errors; + private final IChannel channel; + private final DoneOpenChannel done; + + OpenChannelListener(Collection<Throwable> errors, IChannel channel, DoneOpenChannel done) { + this.errors = errors; + this.channel = channel; + this.done = done; + channel.addChannelListener(this); + } + + public void onChannelOpened() { + channel.removeChannelListener(this); + done.doneOpenChannel(channel); + } + + public void congestionLevel(int level) { + } + + public void onChannelClosed(Throwable e) { + errors.add(e); + channel.removeChannelListener(this); + done.doneOpenChannel(null); + } + } + + private void openChannel(String path, final Collection<Throwable> errors, final DoneOpenChannel done) { + assert Protocol.isDispatchThread(); + try { + int i = path.lastIndexOf('/'); + if (i < 0) { + IPeer peer = Protocol.getLocator().getPeers().get(path); + if (peer == null) { + errors.add(new Exception("Peer not found: " + path)); + done.doneOpenChannel(null); + return; + } + new OpenChannelListener(errors, peer.openChannel(), done); + } + else { + final String id = path.substring(i + 1); + openChannel(path.substring(0, i), errors, new DoneOpenChannel() { + public void doneOpenChannel(IChannel channel) { + if (errors.size() > 0) { + if (channel != null) channel.close(); + done.doneOpenChannel(null); + } + else { + channel.redirect(id); + new OpenChannelListener(errors, channel, done); + } + } + }); + } + } + catch (Throwable x) { + errors.add(x); + done.doneOpenChannel(null); + } + } + + private void runDiagnostics(TreeItem item, boolean loop) { + final Shell shell = new Shell(getShell(), SWT.TITLE | SWT.PRIMARY_MODAL); + GridLayout layout = new GridLayout(); + layout.verticalSpacing = 0; + layout.numColumns = 2; + shell.setLayout(layout); + shell.setText("Running Diagnostics..."); + CLabel label = new CLabel(shell, SWT.NONE); + label.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false)); + label.setText("Running Diagnostics..."); + final TCFSelfTest[] test = new TCFSelfTest[1]; + Button button_cancel = new Button(shell, SWT.PUSH); + button_cancel.setText("&Cancel"); + button_cancel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false)); + button_cancel.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + Protocol.invokeLater(new Runnable() { + public void run() { + if (test[0] != null) test[0].cancel(); + } + }); + } + }); + createVerticalSpacer(shell, 0); + ProgressBar bar = new ProgressBar(shell, SWT.HORIZONTAL); + bar.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1)); + shell.setDefaultButton(button_cancel); + shell.pack(); + shell.setSize(483, shell.getSize().y); + Rectangle rc0 = getShell().getBounds(); + Rectangle rc1 = shell.getBounds(); + shell.setLocation(rc0.x + (rc0.width - rc1.width) / 2, rc0.y + (rc0.height - rc1.height) / 2); + shell.setVisible(true); + runDiagnostics(item, loop, test, shell, label, bar); + } + + private void runDiagnostics(final TreeItem item, final boolean loop, final TCFSelfTest[] test, + final Shell shell, final CLabel label, final ProgressBar bar) { + final TCFSelfTest.TestListener done = new TCFSelfTest.TestListener() { + private String last_text = ""; + private int last_count = 0; + private int last_total = 0; + public void progress(final String label_text, final int count_done, final int count_total) { + if ((label_text == null || last_text.equals(label_text)) && + last_total == count_total && + (count_done - last_count) / (float)count_total < 0.02f) return; + if (label_text != null) last_text = label_text; + last_total = count_total; + last_count = count_done; + display.asyncExec(new Runnable() { + public void run() { + label.setText(last_text); + bar.setMinimum(0); + bar.setMaximum(last_total); + bar.setSelection(last_count); + } + }); + } + public void done(final Collection<Throwable> errors) { + final boolean b = test[0] == null ? false : test[0].isCanceled(); + test[0] = null; + display.asyncExec(new Runnable() { + public void run() { + if (errors.size() > 0) { + shell.dispose(); + new TestErrorsDialog(getControl().getShell(), + getImage("icons/tcf.gif"), errors).open(); + } + else if (loop && !b) { + runDiagnostics(item, true, test, shell, label, bar); + } + else { + shell.dispose(); + } + } + }); + } + }; + findPeer(item, new DoneFindPeer() { + public void doneFindPeer(Collection<Throwable> errors, IPeer peer) { + if (errors.size() > 0) { + done.done(errors); + } + else { + try { + test[0] = new TCFSelfTest(peer, done); + } + catch (Throwable x) { + errors.add(x); + done.done(errors); + } + } + } + }); + } + + private void fillItem(TreeItem item, PeerInfo info) { + String text[] = new String[5]; + text[0] = info.attrs.get(IPeer.ATTR_NAME); + text[1] = info.attrs.get(IPeer.ATTR_OS_NAME); + text[2] = info.attrs.get(IPeer.ATTR_TRANSPORT_NAME); + text[3] = info.attrs.get(IPeer.ATTR_IP_HOST); + text[4] = info.attrs.get(IPeer.ATTR_IP_PORT); + item.setText(text); + item.setImage(getImage(getImageName(info))); + if (info.children == null) loadPeerInfo(info); + item.setItemCount(info.children.length); + } + + private String getPath(PeerInfo info) { + String id = info.attrs.get(IPeer.ATTR_ID); + if (info.parent == null) return id; + return getPath(info.parent) + "/" + id; + } + + private Image getImage(String name) { + if (name == null) return null; + if (display == null) return null; + Image image = image_cache.get(name); + if (image == null) { + URL url = FileLocator.find(TCFUI.getDefault().getBundle(), new Path(name), null); + ImageDescriptor descriptor = null; + if (url == null) { + descriptor = ImageDescriptor.getMissingImageDescriptor(); + } + else { + descriptor = ImageDescriptor.createFromURL(url); + } + image = descriptor.createImage(display); + image_cache.put(name, image); + } + return image; + } + + private String getImageName(PeerInfo info) { + return "icons/tcf.gif"; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java new file mode 100644 index 000000000..84208836d --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java @@ -0,0 +1,1207 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.launch; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import com.windriver.tcf.api.protocol.IChannel; +import com.windriver.tcf.api.protocol.IPeer; +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.services.IBreakpoints; +import com.windriver.tcf.api.services.IDiagnostics; +import com.windriver.tcf.api.services.IFileSystem; +import com.windriver.tcf.api.services.ILineNumbers; +import com.windriver.tcf.api.services.IMemory; +import com.windriver.tcf.api.services.IRegisters; +import com.windriver.tcf.api.services.IRunControl; +import com.windriver.tcf.api.services.IDiagnostics.ISymbol; +import com.windriver.tcf.api.services.IFileSystem.DirEntry; +import com.windriver.tcf.api.services.IFileSystem.FileAttrs; +import com.windriver.tcf.api.services.IFileSystem.FileSystemException; +import com.windriver.tcf.api.services.IFileSystem.IFileHandle; +import com.windriver.tcf.api.services.ILineNumbers.CodeArea; +import com.windriver.tcf.api.services.IMemory.MemoryContext; +import com.windriver.tcf.api.services.IMemory.MemoryError; +import com.windriver.tcf.api.services.IRegisters.RegistersContext; +import com.windriver.tcf.api.services.IRunControl.RunControlContext; +import com.windriver.tcf.api.util.TCFFileInputStream; +import com.windriver.tcf.api.util.TCFFileOutputStream; + +class TCFSelfTest { + + private final static int NUM_CHANNELS = 4; + + private final TestListener listener; + private final IChannel[] channels; + private final LinkedList<Runnable> pending_tests = new LinkedList<Runnable>(); + private final Map<Test,IChannel> active_tests = new HashMap<Test,IChannel>(); + private final Collection<Throwable> errors = new ArrayList<Throwable>(); + + private int count_total; + private int count_done; + private boolean canceled; + private boolean memory_lock; + + public interface TestListener { + public void progress(String label, int done, int total); + public void done(Collection<Throwable> errors); + } + + @SuppressWarnings("serial") + private static class CancelException extends Exception { + CancelException() { + super("Canceled"); + } + } + + private interface Test { + } + + TCFSelfTest(IPeer peer, TestListener listener) throws IOException { + this.listener = listener; + pending_tests.add(new Runnable() { + public void run() { + for (IChannel channel : channels) new TestEcho(channel); + } + }); + pending_tests.add(new Runnable() { + public void run() { + int i = 0; + for (IChannel channel : channels) new TestRCBP1(channel, i++); + } + }); + pending_tests.add(new Runnable() { + public void run() { + for (IChannel channel : channels) new TestFileSystem(channel); + } + }); + pending_tests.add(new Runnable() { + public void run() { + for (int i = 0; i < channels.length; i++) { + switch (i % 3) { + case 0: new TestEcho(channels[i]); break; + case 1: new TestRCBP1(channels[i], i); break; + case 2: new TestFileSystem(channels[i]); break; + } + } + } + }); + count_total = NUM_CHANNELS * pending_tests.size() * 2; + channels = new IChannel[NUM_CHANNELS]; + listener.progress("Openning communication channels...", count_done, count_total); + for (int i = 0; i < channels.length; i++) { + final IChannel channel = channels[i] = peer.openChannel(); + channel.addChannelListener(new IChannel.IChannelListener() { + + public void onChannelOpened() { + for (int i = 0; i < channels.length; i++) { + if (channels[i] == null) return; + if (channels[i].getState() != IChannel.STATE_OPEN) return; + } + runNextTest(); + } + + public void congestionLevel(int level) { + } + + public void onChannelClosed(Throwable error) { + channel.removeChannelListener(this); + if (error == null && (!active_tests.isEmpty() || !pending_tests.isEmpty())) { + error = new IOException("Remote peer closed connection before all tests finished"); + } + int cnt = 0; + for (int i = 0; i < channels.length; i++) { + if (channels[i] == channel) { + channels[i] = null; + if (error != null && !(error instanceof CancelException)) errors.add(error); + for (Iterator<Test> n = active_tests.keySet().iterator(); n.hasNext();) { + if (active_tests.get(n.next()) == channel) n.remove(); + } + } + else if (channels[i] != null) { + cnt++; + } + } + if (cnt == 0) { + TCFSelfTest.this.listener.done(errors); + } + else if (active_tests.isEmpty()) { + for (int i = 0; i < channels.length; i++) { + if (channels[i] != null && channels[i].getState() != IChannel.STATE_CLOSED) { + if (errors.isEmpty()) channels[i].close(); + else channels[i].terminate(new CancelException()); + } + } + } + } + }); + } + } + + void cancel() { + if (canceled) return; + for (final Test t : active_tests.keySet()) { + if (t instanceof TestRCBP1) { + ((TestRCBP1)t).cancel(new Runnable() { + public void run() { + assert active_tests.get(t) == null; + cancel(); + } + }); + return; + } + } + canceled = true; + for (IChannel c : channels) { + if (c != null && c.getState() != IChannel.STATE_CLOSED) { + c.terminate(new CancelException()); + } + } + } + + boolean isCanceled() { + return canceled; + } + + private class TestEcho implements Test, IDiagnostics.DoneEcho { + + private final IDiagnostics diag; + private final LinkedList<String> msgs = new LinkedList<String>(); + private int count = 0; + + TestEcho(IChannel channel) { + diag = channel.getRemoteService(IDiagnostics.class); + listener.progress("Running Echo Test...", ++count_done, count_total); + active_tests.put(this, channel); + if (diag == null) { + done(this); + } + else { + for (int i = 0; i < 32; i++) sendMessage(); + } + } + + private void sendMessage() { + StringBuffer buf = new StringBuffer(); + buf.append(Integer.toHexString(count)); + for (int i = 0; i < 64; i++) { + buf.append('-'); + buf.append((char)(0x400 * i + count)); + } + String s = buf.toString(); + msgs.add(s); + diag.echo(s, this); + count++; + } + + public void doneEcho(IToken token, Throwable error, String b) { + String s = msgs.removeFirst(); + if (active_tests.get(this) == null) return; + if (error != null) { + errors.add(error); + done(this); + } + else if (!s.equals(b)) { + errors.add(new Exception("Echo test failed: " + s + " != " + b)); + done(this); + } + else if (count < 0x400) { + sendMessage(); + } + else if (msgs.isEmpty()){ + done(this); + } + } + } + + private class TestRCBP1 implements Test, + IDiagnostics.DoneGetTestList, IDiagnostics.DoneRunTest, + IRunControl.DoneGetContext, IRunControl.DoneGetChildren, + IRunControl.DoneGetState, IRunControl.RunControlListener, + IDiagnostics.DoneGetSymbol { + + private final int channel_id; + private final IDiagnostics diag; + private final IMemory mm; + private final IRunControl rc; + private final IRegisters rg; + private final IBreakpoints bp; + private final ILineNumbers ln; + private final Map<String,IRunControl.RunControlContext> threads = new HashMap<String,IRunControl.RunControlContext>(); + private final Map<String,SuspendedContext> suspended = new HashMap<String,SuspendedContext>(); + private final Map<String,SuspendedContext> suspended_prev = new HashMap<String,SuspendedContext>(); + private final Set<String> running = new HashSet<String>(); + private final Map<IToken,String> get_state_cmds = new HashMap<IToken,String>(); + private final Map<String,Map<String,IRegisters.RegistersContext>> regs = + new HashMap<String,Map<String,IRegisters.RegistersContext>>(); + + private String context_id; // Test process context ID + private IRunControl.RunControlContext context; + private String main_thread_id; + private Runnable pending_cancel; + private ISymbol func0; + private ISymbol func1; + private ISymbol func2; + private ISymbol array; + private int bp_cnt = 0; + + private class SuspendedContext { + final String id; + final String pc; + final String reason; + final Map<String,Object> params; + boolean resumed; + + SuspendedContext(String id, String pc, String reason, Map<String,Object> params) { + this.id = id; + this.pc = pc; + this.reason = reason; + this.params = params; + } + } + + TestRCBP1(IChannel channel, int channel_id) { + this.channel_id = channel_id; + diag = channel.getRemoteService(IDiagnostics.class); + mm = channel.getRemoteService(IMemory.class); + rc = channel.getRemoteService(IRunControl.class); + rg = channel.getRemoteService(IRegisters.class); + bp = channel.getRemoteService(IBreakpoints.class); + ln = channel.getRemoteService(ILineNumbers.class); + active_tests.put(this, channel); + listener.progress("Running Run Control Test...", ++count_done, count_total); + if (diag == null || rc == null) { + done(this); + } + else if (bp == null) { + exit(new Exception("Remote Breakpoints service not found")); + } + else { + diag.getTestList(this); + } + } + + public void doneGetTestList(IToken token, Throwable error, String[] list) { + assert active_tests.get(this) != null; + if (error != null) { + exit(error); + } + else { + for (int i = 0; i < list.length; i++) { + if (list[i].equals("RCBP1")) { + diag.runTest("RCBP1", this); + return; + } + } + } + exit(null); + } + + public void doneRunTest(IToken token, Throwable error, String context_id) { + assert active_tests.get(this) != null; + assert this.context_id == null; + if (error != null) { + exit(error); + } + else { + this.context_id = context_id; + if (pending_cancel != null) { + Protocol.invokeLater(pending_cancel); + pending_cancel = null; + } + else { + diag.getSymbol(context_id, "tcf_test_func0", this); + diag.getSymbol(context_id, "tcf_test_func1", this); + diag.getSymbol(context_id, "tcf_test_func2", this); + diag.getSymbol(context_id, "tcf_test_array", this); + } + } + } + + @SuppressWarnings("unchecked") + public void doneGetSymbol(IToken token, Throwable error, ISymbol symbol) { + assert active_tests.get(this) != null; + assert this.context_id != null; + if (error != null) { + exit(error); + } + else if (!symbol.isGlobal()) { + exit(new Exception("Symbols 'tcf_test_*' must be global")); + } + else if (!symbol.isAbs()) { + exit(new Exception("Symbols 'tcf_test_*' must be absolute")); + } + else if (func0 == null) { + func0 = symbol; + } + else if (func1 == null) { + func1 = symbol; + } + else if (func2 == null) { + func2 = symbol; + } + else { + array = symbol; + Map<String,Object> m[] = new Map[4]; + for (int i = 0; i < m.length; i++) { + m[i] = new HashMap(); + m[i].put(IBreakpoints.PROP_ID, "TcfTestBP" + i); + m[i].put(IBreakpoints.PROP_ENABLED, Boolean.TRUE); + switch (i) { + case 0: + m[i].put(IBreakpoints.PROP_ADDRESS, func0.getValue().toString()); + m[i].put(IBreakpoints.PROP_CONDITION, "$thread!=\"\""); + break; + case 1: + m[i].put(IBreakpoints.PROP_ADDRESS, "(31+1)/16+tcf_test_func1-2"); + m[i].put(IBreakpoints.PROP_CONDITION, "tcf_test_func0!=tcf_test_func1"); + break; + case 2: + m[i].put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2"); + m[i].put(IBreakpoints.PROP_ENABLED, Boolean.FALSE); + break; + case 3: + m[i].put(IBreakpoints.PROP_ID, "TcfTestBP3" + channel_id); + m[i].put(IBreakpoints.PROP_ENABLED, Boolean.FALSE); + m[i].put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2"); + break; + } + } + bp.set(m, new IBreakpoints.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error != null) { + exit(error); + } + else { + rc.getContext(context_id, TestRCBP1.this); + } + } + }); + } + } + + public void doneGetContext(IToken token, Exception error, RunControlContext context) { + if (canceled) return; + if (error != null) { + exit(error); + } + else { + if (this.context == null) { + this.context = context; + assert context_id.equals(context.getID()); + assert threads.isEmpty(); + assert running.isEmpty(); + assert suspended.isEmpty(); + rc.addListener(this); + } + rc.getChildren(context.getID(), this); + if (context.hasState()) { + threads.put(context.getID(), context); + get_state_cmds.put(context.getState(this), context.getID()); + } + } + } + + public void doneGetChildren(IToken token, Exception error, String[] contexts) { + if (canceled) return; + if (error != null) { + exit(error); + } + else { + for (String id : contexts) rc.getContext(id, this); + } + } + + public void doneGetState(IToken token, Exception error, + boolean suspended, String pc, String reason, + Map<String, Object> params) { + final String id = get_state_cmds.remove(token); + if (canceled) return; + if (id == null) { + exit(new Exception("Invalid getState responce")); + } + else if (!suspended) { + if (this.suspended.get(id) != null) { + exit(new Exception("Invalid result of getState command")); + } + else { + running.add(id); + } + } + else { + assert threads.get(id) != null; + if (running.contains(id)) { + exit(new Exception("Invalid result of getState command")); + } + else { + SuspendedContext sc = this.suspended.get(id); + if (sc != null) { + if (!sc.pc.equals(pc) || !sc.reason.equals(reason)) { + exit(new Exception("Invalid result of getState command")); + } + else { + resume(sc); + } + } + else { + if (main_thread_id != null) { + exit(new Exception("Missing contextSuspended event for " + id)); + } + else if ("Breakpoint".equals(reason)) { + exit(new Exception("Invalid suspend reason of main thread after test start: " + reason + " " + pc)); + } + else { + main_thread_id = id; + final SuspendedContext sx = new SuspendedContext(id, pc, reason, params); + this.suspended.put(id, sx); + final String bp_id = "TcfTestBP3" + channel_id; + Map<String,Object> m = new HashMap<String,Object>(); + m.put(IBreakpoints.PROP_ID, bp_id); + m.put(IBreakpoints.PROP_ENABLED, Boolean.FALSE); + m.put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2"); + m.put(IBreakpoints.PROP_CONDITION, "$thread==\"" + id + "\""); + bp.change(m, new IBreakpoints.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error != null) exit(error); + } + }); + Protocol.sync(new Runnable() { + public void run() { + bp.enable(new String[]{ bp_id }, new IBreakpoints.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (error != null) exit(error); + } + }); + resume(sx); + } + }); + } + } + } + } + } + + public void containerResumed(String[] context_ids) { + for (String id : context_ids) contextResumed(id); + } + + public void containerSuspended(String context, String pc, + String reason, Map<String, Object> params, + String[] suspended_ids) { + for (String id : suspended_ids) { + if (id.equals(context)) continue; + contextSuspended(id, null, null, null); + } + contextSuspended(context, pc, reason, params); + } + + public void contextAdded(RunControlContext[] contexts) { + for (int i = 0; i < contexts.length; i++) { + if (threads.get(contexts[i].getID()) != null) { + exit(new Exception("Invalid contextAdded event")); + return; + } + if (context.getID().equals(contexts[i].getProperties().get("ParentID"))) { + threads.put(contexts[i].getID(), contexts[i]); + running.add(contexts[i].getID()); + } + } + } + + public void contextChanged(RunControlContext[] contexts) { + for (int i = 0; i < contexts.length; i++) { + if (contexts[i].getID().equals(context.getID())) { + context = contexts[i]; + } + if (context.getID().equals(contexts[i].getProperties().get("ProcessID"))) { + threads.put(contexts[i].getID(), contexts[i]); + } + } + } + + public void contextException(String context, String msg) { + if (context.equals(this.context.getID()) || threads.get(context) != null) { + exit(new Exception(msg)); + } + } + + public void contextRemoved(String[] contexts) { + for (String id : contexts) { + if (suspended.get(id) != null) { + exit(new Exception("Invalid contextRemoved event")); + return; + } + threads.remove(id); + running.remove(id); + if (threads.isEmpty()) { + if (bp_cnt != 30) { + exit(new Exception("Test main thread breakpoint count = " + bp_cnt + ", expected 30")); + } + rc.removeListener(this); + // Flush communication channel of pending commands + Protocol.sync(new Runnable() { + public void run() { + exit(null); + } + }); + } + } + } + + public void contextResumed(String id) { + if (threads.get(id) == null) return; + SuspendedContext sc = suspended.remove(id); + if (!isAlienBreakpoint(sc)) suspended_prev.put(id, sc); + running.add(id); + } + + private String toSymName(long addr) { + if (func0.getValue().longValue() == addr) return "tcf_test_func0"; + if (func1.getValue().longValue() == addr) return "tcf_test_func1"; + if (func2.getValue().longValue() == addr) return "tcf_test_func2"; + return "*no name*"; + } + + private void checkSuspendedContext(SuspendedContext sp, ISymbol sym) { + long pc = Long.parseLong(sp.pc); + if (pc != sym.getValue().longValue() || !"Breakpoint".equals(sp.reason)) { + exit(new Exception("Invalid contextSuspended event: " + sp.id + " '" + toSymName(pc) + "' " + sp.pc + " " + sp.reason + + ", expected breakpoint at '" + toSymName(sym.getValue().longValue()) + "' " + sym.getValue())); + } + } + + private boolean isAlienBreakpoint(SuspendedContext sc) { + // Check if context suspended by a breakpoint from another debug session + // Test should ignore such breakpoints. + if (!"Breakpoint".equals(sc.reason)) return false; + long pc = Long.parseLong(sc.pc); + if (pc == func0.getValue().longValue()) return false; + if (pc == func1.getValue().longValue()) return false; + if (pc == func2.getValue().longValue()) return false; + return true; + } + + public void contextSuspended(String id, String pc, String reason, Map<String, Object> params) { + if (threads.get(id) == null) return; + assert main_thread_id != null; + running.remove(id); + SuspendedContext sc = suspended.get(id); + if (sc != null) { + if (!sc.pc.equals(pc) || !sc.reason.equals(reason)) { + exit(new Exception("Invalid contextSuspended event")); + } + } + else { + sc = new SuspendedContext(id, pc, reason, params); + suspended.put(id, sc); + if (!isAlienBreakpoint(sc)) { + if ("Breakpoint".equals(reason) && id.equals(main_thread_id)) bp_cnt++; + SuspendedContext sp = suspended_prev.get(id); + if (sp != null) { + if (Long.parseLong(sc.pc) == func2.getValue().longValue()) { + checkSuspendedContext(sp, func1); + } + else if (Long.parseLong(sc.pc) == func1.getValue().longValue()) { + checkSuspendedContext(sp, func0); + } + else if (Long.parseLong(sc.pc) == func0.getValue().longValue()) { + if (id.equals(main_thread_id)) { + if ("Breakpoint".equals(sp.reason)) { + checkSuspendedContext(sp, func2); + } + } + else { + checkSuspendedContext(sp, func1); + } + } + } + } + } + final SuspendedContext sc0 = sc; + ILineNumbers.DoneMapToSource ln_done = new ILineNumbers.DoneMapToSource() { + public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) { + if (error != null) exit(error); + if (mm != null) runMemoryTest(sc0); + else if (rg != null) runRegistersTest(sc0); + else resume(sc0); + } + }; + if (ln != null) { + BigInteger x = new BigInteger(pc); + BigInteger y = x.add(BigInteger.valueOf(1)); + ln.mapToSource(id, x, y, ln_done); + } + else { + ln_done.doneMapToSource(null, null, null); + } + } + + private void resume(final SuspendedContext sc) { + IRunControl.RunControlContext ctx = threads.get(sc.id); + if (ctx != null && !sc.resumed) { + sc.resumed = true; + ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (canceled) return; + if (active_tests.get(this) == null) return; + if (threads.get(sc.id) == null) return; + if (error != null) exit(error); + } + }); + } + } + + private void runMemoryTest(final SuspendedContext sc) { + if (memory_lock) { + resume(sc); + return; + } + memory_lock = true; + mm.getContext(context_id, new IMemory.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, final MemoryContext mem_ctx) { + if (error != null) { + exit(error); + return; + } + if (!context_id.equals(mem_ctx.getID())) { + exit(new Exception("Bad memory context data: invalid ID")); + } + Object pid = context.getProperties().get("ProcessID"); + if (pid != null && !pid.equals(mem_ctx.getProperties().get("ProcessID"))) { + exit(new Exception("Bad memory context data: invalid ProcessID")); + } + final boolean big_endian = mem_ctx.isBigEndian(); + final int addr_size = mem_ctx.getAddressSize(); + final byte[] buf = new byte[0x1000]; + mem_ctx.get(array.getValue(), 1, buf, 0, addr_size, 0, new IMemory.DoneMemory() { + public void doneMemory(IToken token, MemoryError error) { + byte[] tmp = new byte[addr_size + 1]; + tmp[0] = 0; // Extra byte to avoid sign extension by BigInteger + if (big_endian) { + System.arraycopy(buf, 0, tmp, 1, addr_size); + } + else { + for (int i = 0; i < addr_size; i++) { + tmp[i + 1] = buf[addr_size - i - 1]; + } + } + Number mem_address = new BigInteger(tmp); + testSetMemoryCommand(sc, mem_ctx, mem_address, buf); + } + }); + } + }); + } + + private void testSetMemoryCommand(final SuspendedContext sc, + final IMemory.MemoryContext mem_ctx, + final Number addr, final byte[] buf) { + final byte[] data = new byte[buf.length]; + new Random().nextBytes(data); + mem_ctx.set(addr, 1, data, 0, data.length, 0, new IMemory.DoneMemory() { + public void doneMemory(IToken token, MemoryError error) { + if (error != null) { + exit(error); + return; + } + mem_ctx.get(addr, 1, buf, 0, buf.length, 0, new IMemory.DoneMemory() { + public void doneMemory(IToken token, MemoryError error) { + if (error != null) { + exit(error); + return; + } + for (int i = 0; i < data.length; i++) { + if (data[i] != buf[i]) { + exit(new Exception( + "Invalid Memory.get responce: wrong data at offset " + i + + ", expected " + data[i] + ", actual " + buf[i])); + return; + } + } + testFillMemoryCommand(sc, mem_ctx, addr, buf); + } + }); + } + }); + } + + private void testFillMemoryCommand(final SuspendedContext sc, + final IMemory.MemoryContext mem_ctx, + final Number addr, final byte[] buf) { + final byte[] data = new byte[buf.length / 7]; + new Random().nextBytes(data); + mem_ctx.fill(addr, 1, data, buf.length, 0, new IMemory.DoneMemory() { + public void doneMemory(IToken token, MemoryError error) { + if (error != null) { + exit(error); + return; + } + mem_ctx.get(addr, 1, buf, 0, buf.length, 0, new IMemory.DoneMemory() { + public void doneMemory(IToken token, MemoryError error) { + if (error != null) { + exit(error); + return; + } + for (int i = 0; i < data.length; i++) { + if (data[i % data.length] != buf[i]) { + exit(new Exception( + "Invalid Memory.get responce: wrong data at offset " + i + + ", expected " + data[i % data.length] + ", actual " + buf[i])); + return; + } + } + memory_lock = false; + if (rg != null) runRegistersTest(sc); + else resume(sc); + } + }); + } + }); + } + + private void runRegistersTest(final SuspendedContext sc) { + if (regs.get(sc.id) == null) { + final Map<String,IRegisters.RegistersContext> reg_map = + new HashMap<String,IRegisters.RegistersContext>(); + final Set<IToken> cmds = new HashSet<IToken>(); + regs.put(sc.id, reg_map); + cmds.add(rg.getChildren(sc.id, new IRegisters.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] context_ids) { + cmds.remove(token); + if (error != null) { + for (IToken t : cmds) t.cancel(); + exit(error); + return; + } + for (final String id : context_ids) { + cmds.add(rg.getChildren(id, this)); + cmds.add(rg.getContext(id, new IRegisters.DoneGetContext() { + public void doneGetContext(IToken token, + Exception error, + RegistersContext context) { + cmds.remove(token); + if (error != null) { + for (IToken t : cmds) t.cancel(); + exit(error); + return; + } + reg_map.put(id, context); + if (cmds.isEmpty()) { + testGetSetRegisterCommands(sc); + } + } + })); + } + } + })); + } + else { + testGetSetRegisterCommands(sc); + } + } + + private void testGetSetRegisterCommands(final SuspendedContext sc) { + final Set<IToken> cmds = new HashSet<IToken>(); + Map<String,IRegisters.RegistersContext> reg_map = regs.get(sc.id); + for (final IRegisters.RegistersContext ctx : reg_map.values()) { + if (!ctx.isReadable()) continue; + if (ctx.isReadOnce()) continue; + String[] fmts = ctx.getAvailableFormats(); + for (final String fmt : fmts) { + cmds.add(ctx.get(fmt, new IRegisters.DoneGet() { + public void doneGet(IToken token, Exception error, String value) { + cmds.remove(token); + if (error != null) { + for (IToken t : cmds) t.cancel(); + exit(error); + return; + } + cmds.add(ctx.set(fmt, value, new IRegisters.DoneSet() { + public void doneSet(IToken token, Exception error) { + cmds.remove(token); + if (error != null) { + for (IToken t : cmds) t.cancel(); + exit(error); + return; + } + if (cmds.isEmpty()) { + resume(sc); + } + } + })); + } + })); + } + } + if (cmds.isEmpty()) { + resume(sc); + } + } + + void cancel(final Runnable done) { + if (rc != null) rc.removeListener(this); + if (context_id == null) { + if (pending_cancel != null) { + exit(null); + } + else { + pending_cancel = done; + } + } + else { + diag.cancelTest(context_id, new IDiagnostics.DoneCancelTest() { + public void doneCancelTest(IToken token, Throwable error) { + exit(error); + done.run(); + } + }); + } + } + + private void exit(Throwable x) { + if (active_tests.get(this) == null) return; + if (pending_cancel != null) { + pending_cancel.run(); + pending_cancel = null; + } + else { + if (x != null) errors.add(x); + if (rc != null) rc.removeListener(this); + } + done(this); + } + } + + private int file_count = 0; + + private class TestFileSystem implements Test, IFileSystem.DoneStat, + IFileSystem.DoneOpen, IFileSystem.DoneClose, + IFileSystem.DoneWrite, IFileSystem.DoneRead, + IFileSystem.DoneRename, IFileSystem.DoneRealPath, + IFileSystem.DoneRemove, IFileSystem.DoneRoots, + IFileSystem.DoneReadDir { + + private static final int + STATE_PRE = 0, + STATE_WRITE = 1, + STATE_READ = 2, + STATE_OUT = 3, + STATE_INP = 4, + STATE_EXIT = 5; + + private final IFileSystem files; + private final byte[] data = new byte[0x1000]; + private String root; + private String tmp_path; + private String file_name; + private IFileHandle handle; + private int state = STATE_PRE; + + TestFileSystem(IChannel channel) { + files = channel.getRemoteService(IFileSystem.class); + active_tests.put(this, channel); + listener.progress("Running File System Test...", ++count_done, count_total); + if (files == null) { + done(this); + } + else { + files.roots(this); + } + } + + public void doneRoots(IToken token, FileSystemException error, DirEntry[] entries) { + assert state == STATE_PRE; + if (error != null) { + error(error); + } + else if (entries == null || entries.length == 0) { + error(new Exception("Invalid FileSysrem.roots responce: empty roots array")); + } + else { + root = entries[0].filename; + files.opendir(root, this); + } + } + + public void doneReadDir(IToken token, FileSystemException error, + DirEntry[] entries, boolean eof) { + assert state == STATE_PRE; + if (error != null) { + error(error); + } + else { + if (entries != null && tmp_path == null) { + for (DirEntry e : entries) { + if (e.filename.equals("tmp") || e.filename.equalsIgnoreCase("temp")) { + tmp_path = root + "/" + e.filename; + break; + } + } + } + if (eof) { + if (tmp_path == null) { + error(new Exception("File system test filed: cannot find temporary directory")); + return; + } + files.close(handle, this); + } + else { + files.readdir(handle, this); + } + } + } + + public void doneStat(IToken token, FileSystemException error, FileAttrs attrs) { + if (error != null) { + error(error); + } + else if (state == STATE_READ) { + if (attrs.size != data.length) { + error(new Exception("Invalid FileSysrem.fstat responce: wrong file size")); + } + else { + files.close(handle, this); + } + } + else { + file_name = tmp_path + "/tcf-test-" + (file_count++) + ".tmp"; + files.open(file_name, IFileSystem.O_CREAT | IFileSystem.O_TRUNC | IFileSystem.O_WRITE, null, this); + } + } + + public void doneOpen(IToken token, FileSystemException error, final IFileHandle handle) { + if (error != null) { + error(error); + } + else { + this.handle = handle; + if (state == STATE_READ) { + files.read(handle, 0, data.length + 1, this); + } + else if (state == STATE_WRITE) { + new Random().nextBytes(data); + files.write(handle, 0, data, 0, data.length, this); + } + else if (state == STATE_INP) { + Thread thread = new Thread() { + public void run() { + try { + InputStream inp = new TCFFileInputStream(handle); + int i = 0; + for (;;) { + int ch = inp.read(); + if (ch < 0) break; + int dt = data[i % data.length] & 0xff; + if (ch != dt) { + error(new Exception("Invalid TCFFileInputStream.read responce: wrong data at offset " + i + + ", expected " + dt + ", actual " + ch)); + } + i++; + } + if (i != data.length * 16) { + error(new Exception("Invalid TCFFileInputStream.read responce: wrong file length: " + + "expected " + data.length + ", actual " + i)); + } + inp.close(); + Protocol.invokeLater(new Runnable() { + public void run() { + state = STATE_EXIT; + files.rename(file_name, file_name + ".rnm", TestFileSystem.this); + } + }); + } + catch (Throwable x) { + error(x); + } + } + private void error(final Throwable x) { + Protocol.invokeLater(new Runnable() { + public void run() { + TestFileSystem.this.error(x); + } + }); + } + }; + thread.setName("TCF FileSystem Test"); + thread.start(); + } + else if (state == STATE_OUT) { + new Random().nextBytes(data); + Thread thread = new Thread() { + public void run() { + try { + OutputStream out = new TCFFileOutputStream(handle); + for (int i = 0; i < data.length * 16; i++) { + out.write(data[i % data.length] & 0xff); + } + out.close(); + Protocol.invokeLater(new Runnable() { + public void run() { + state = STATE_INP; + files.open(file_name, IFileSystem.O_READ, null, TestFileSystem.this); + } + }); + } + catch (Throwable x) { + error(x); + } + } + private void error(final Throwable x) { + Protocol.invokeLater(new Runnable() { + public void run() { + TestFileSystem.this.error(x); + } + }); + } + }; + thread.setName("TCF FileSystem Test"); + thread.start(); + } + else { + assert state == STATE_PRE; + files.readdir(handle, this); + } + } + } + + public void doneWrite(IToken token, FileSystemException error) { + if (error != null) { + error(error); + } + else { + files.close(handle, this); + } + } + + public void doneRead(IToken token, FileSystemException error, byte[] data, boolean eof) { + if (error != null) { + error(error); + } + else if (!eof) { + error(new Exception("Invalid FileSysrem.read responce: EOF expected")); + } + else if (data.length != this.data.length) { + error(new Exception("Invalid FileSysrem.read responce: wrong data array size")); + } + else { + for (int i = 0; i < data.length; i++) { + if (data[i] != this.data[i]) { + error(new Exception("Invalid FileSysrem.read responce: wrong data at offset " + i + + ", expected " + this.data[i] + ", actual " + data[i])); + return; + } + } + files.fstat(handle, this); + } + } + + public void doneClose(IToken token, FileSystemException error) { + if (error != null) { + error(error); + } + else { + handle = null; + if (state == STATE_PRE) { + files.realpath(tmp_path, this); + } + else if (state == STATE_WRITE) { + state = STATE_READ; + files.open(file_name, IFileSystem.O_READ, null, this); + } + else if (state == STATE_READ) { + state = STATE_OUT; + files.open(file_name, IFileSystem.O_WRITE, null, this); + } + else { + assert false; + } + } + } + + public void doneRename(IToken token, FileSystemException error) { + assert state == STATE_EXIT; + if (error != null) { + error(error); + } + else { + files.realpath(file_name + ".rnm", this); + } + } + + public void doneRealPath(IToken token, FileSystemException error, String path) { + if (error != null) { + error(error); + } + else if (state == STATE_PRE) { + state = STATE_WRITE; + tmp_path = path; + files.stat(tmp_path, this); + } + else if (!path.equals(file_name + ".rnm")) { + error(new Exception("Invalid FileSysrem.realpath responce: " + path)); + } + else { + files.remove(file_name + ".rnm", this); + } + } + + public void doneRemove(IToken token, FileSystemException error) { + assert state == STATE_EXIT; + if (error != null) { + error(error); + } + else { + done(this); + } + } + + private void error(Throwable x) { + if (active_tests.get(this) == null) return; + errors.add(x); + done(this); + } + } + + private void done(Test test) { + assert active_tests.get(test) != null; + active_tests.remove(test); + listener.progress(null, ++count_done, count_total); + if (active_tests.isEmpty()) runNextTest(); + } + + private void runNextTest() { + while (active_tests.isEmpty()) { + if (canceled || errors.size() > 0 || pending_tests.size() == 0) { + for (IChannel channel : channels) { + if (channel != null && channel.getState() != IChannel.STATE_CLOSED) { + if (errors.isEmpty()) channel.close(); + else channel.terminate(new CancelException()); + } + } + return; + } + pending_tests.removeFirst().run(); + } + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java new file mode 100644 index 000000000..8d06cafd5 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.launch; + +import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup; +import org.eclipse.debug.ui.CommonTab; +import org.eclipse.debug.ui.EnvironmentTab; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.debug.ui.ILaunchConfigurationTab; +import org.eclipse.debug.ui.sourcelookup.SourceLookupTab; + +/** + * Launch configuration dialog tab group for Target Communication Framework + */ +public class TCFTabGroup extends AbstractLaunchConfigurationTabGroup { + + public void createTabs(ILaunchConfigurationDialog dialog, String mode) { + setTabs(new ILaunchConfigurationTab[] { + new TCFMainTab(), + new TCFArgumentsTab(), + new EnvironmentTab(), + new SourceLookupTab(), + new CommonTab() + }); + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java new file mode 100644 index 000000000..312e85c9a --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.launch; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collection; +import java.util.Iterator; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +class TestErrorsDialog extends Dialog { + + private final int SIZING_TEXT_WIDTH = 600; + private final int SIZING_TEXT_HEIGHT = 400; + + private Collection<Throwable> errors; + private Image image; + private Text text; + + TestErrorsDialog(Shell parent, Image image, Collection<Throwable> errors) { + super(parent); + this.image = image; + this.errors = errors; + } + + protected void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText("Connection Diagnostic errors"); + shell.setImage(image); + } + + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, "&OK", true); + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite)super.createDialogArea(parent); + composite.setSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + + Label label = new Label(composite, SWT.WRAP); + label.setFont(JFaceResources.getFontRegistry().get(JFaceResources.BANNER_FONT)); + label.setText("Connection diagnostics ended with errors:"); + + text = new Text(composite, SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); + text.setFont(JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT)); + text.setEditable(false); + text.setText(createText()); + GridData data = new GridData(GridData.FILL_BOTH); + data.widthHint = SIZING_TEXT_WIDTH; + data.heightHint = SIZING_TEXT_HEIGHT; + text.setLayoutData(data); + + return composite; + } + + private String createText() { + StringWriter buf = new StringWriter(); + PrintWriter pwr = new PrintWriter(buf); + for (Iterator<Throwable> i = errors.iterator(); i.hasNext();) { + i.next().printStackTrace(pwr); + pwr.println(); + } + pwr.flush(); + return buf.toString(); + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java new file mode 100644 index 000000000..fafd5e541 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import java.util.HashMap; +import java.util.Map; + +public class TCFChildren { + + final TCFNode node; + final Map<String,TCFNode> children = new HashMap<String,TCFNode>(); + final Map<String,TCFNode> children_next = new HashMap<String,TCFNode>(); + + protected boolean valid; + + TCFChildren(TCFNode node) { + this.node = node; + } + + void dispose() { + TCFNode arr[] = children.values().toArray(new TCFNode[children.size()]); + for (int i = 0; i < arr.length; i++) arr[i].dispose(); + assert children.isEmpty(); + } + + void dispose(String id) { + children.remove(id); + } + + void doneValidate() { + valid = true; + TCFNode[] a = children.values().toArray(new TCFNode[children.size()]); + for (TCFNode n : a) { + if (children_next.get(n.id) != n) n.dispose(); + } + for (TCFNode n : children_next.values()) { + if (children.get(n.id) == null) { + children.put(n.id, n); + n.model.addNode(n.id, n); + } + assert children.get(n.id) == n; + } + assert children.size() == children_next.size(); + } + + boolean validate(TCFRunnable done) { + doneValidate(); + return true; + } + + void invalidate() { + children_next.clear(); + TCFNode[] a = children.values().toArray(new TCFNode[children.size()]); + for (int i = 0; i < a.length; i++) a[i].invalidateNode(TCFNode.CF_ALL); + valid = false; + } + + int size() { + return children.size(); + } + + TCFNode[] toArray() { + return children.values().toArray(new TCFNode[children.size()]); + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java new file mode 100644 index 000000000..95229f778 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IMemory; +import com.windriver.tcf.api.services.IRunControl; + +public class TCFChildrenExecContext extends TCFChildren { + + private boolean mem_valid; + private boolean run_valid; + + TCFChildrenExecContext(TCFNode node) { + super(node); + } + + @Override + boolean validate(TCFRunnable done) { + if (!mem_valid && !validateMemoryChildren(done)) return false; + if (!run_valid && !validateRunControlChildren(done)) return false; + doneValidate(); + return true; + } + + @Override + void invalidate() { + mem_valid = false; + run_valid = false; + super.invalidate(); + } + + private boolean validateMemoryChildren(TCFRunnable done) { + assert node.data_command == null; + IMemory mem = node.model.getLaunch().getService(IMemory.class); + if (mem == null) { + mem_valid = true; + return true; + } + if (done != null) node.wait_list.add(done); + node.data_command = mem.getChildren(node.id, new IMemory.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] contexts) { + if (node.data_command != token) return; + node.data_command = null; + if (error != null) { + node.node_error = error; + } + else { + for (int i = 0; i < contexts.length; i++) { + String id = contexts[i]; + TCFNode n = node.model.getNode(id); + if (n == null) n = new TCFNodeExecContext(node, id); + children_next.put(id, n); + } + } + mem_valid = true; + node.validateNode(null); + } + }); + return false; + } + + private boolean validateRunControlChildren(TCFRunnable done) { + assert node.data_command == null; + IRunControl run = node.model.getLaunch().getService(IRunControl.class); + if (run == null) { + run_valid = true; + return true; + } + if (done != null) node.wait_list.add(done); + node.data_command = run.getChildren(node.id, new IRunControl.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] contexts) { + if (node.data_command != token) return; + node.data_command = null; + if (error != null) { + node.node_error = error; + } + else { + for (String id : contexts) { + TCFNode n = node.model.getNode(id); + if (n == null) n = new TCFNodeExecContext(node, id); + children_next.put(id, n); + } + } + run_valid = true; + node.validateNode(null); + } + }); + return false; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java new file mode 100644 index 000000000..ec76afab7 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IRegisters; + +public class TCFChildrenRegisters extends TCFChildren { + + TCFChildrenRegisters(TCFNode node) { + super(node); + } + + @Override + boolean validate(TCFRunnable done) { + children_next.clear(); + String addr = node.getAddress(); + if (addr == null) { + doneValidate(); + return true; + } + IRegisters regs = node.model.getLaunch().getService(IRegisters.class); + if (regs == null) { + doneValidate(); + return true; + } + assert node.data_command == null; + if (done != null) node.wait_list.add(done); + node.data_command = regs.getChildren(node.id, new IRegisters.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] contexts) { + if (node.data_command != token) return; + node.data_command = null; + if (error != null) { + node.node_error = error; + } + else { + for (String id : contexts) { + TCFNode n = node.model.getNode(id); + if (n == null) n = new TCFNodeRegister(node, id); + children_next.put(id, n); + } + } + doneValidate(); + node.validateNode(null); + } + }); + return false; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java new file mode 100644 index 000000000..8bcf2e757 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IStackTrace; + +public class TCFChildrenStackTrace extends TCFChildren { + + private final TCFChildren children_regs; + + TCFChildrenStackTrace(TCFNode node, TCFChildren children_regs) { + super(node); + this.children_regs = children_regs; + } + + @Override + boolean validate(TCFRunnable done) { + children_next.clear(); + String addr = node.getAddress(); + if (addr == null) { + doneValidate(); + return true; + } + String nm = node.id + "-TF"; + TCFNode n = children.get(nm); + if (n == null) n = new TCFNodeStackFrame(node, nm, children_regs); + children_next.put(n.id, n); + IStackTrace st = node.model.getLaunch().getService(IStackTrace.class); + if (st == null) { + doneValidate(); + return true; + } + assert node.data_command == null; + if (done != null) node.wait_list.add(done); + node.data_command = st.getChildren(node.id, new IStackTrace.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] contexts) { + if (node.data_command != token) return; + node.data_command = null; + if (error != null) { + node.node_error = error; + } + else { + int cnt = contexts.length; + for (String id : contexts) { + TCFNode n = node.model.getNode(id); + if (n == null || ((TCFNodeStackFrame)n).getFrameNo() != cnt) { + n = new TCFNodeStackFrame(node, id, cnt); + } + assert ((TCFNodeStackFrame)n).getFrameNo() == cnt; + assert n.id.equals(id); + children_next.put(id, n); + cnt--; + } + } + doneValidate(); + node.validateNode(null); + } + }); + return false; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java new file mode 100644 index 000000000..8881fcb20 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java @@ -0,0 +1,81 @@ +package com.windriver.debug.tcf.ui.model; + +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.jface.resource.ImageDescriptor; + +public class TCFColumnPresentationRegister implements IColumnPresentation { + + public static final String PRESENTATION_ID = "Registers"; + + private static String[] cols_all = { + TCFNodeRegister.COL_NAME, + TCFNodeRegister.COL_HEX_VALUE, + TCFNodeRegister.COL_DEC_VALUE, + TCFNodeRegister.COL_DESCRIPTION, + TCFNodeRegister.COL_READBLE, + TCFNodeRegister.COL_READ_ONCE, + TCFNodeRegister.COL_WRITEABLE, + TCFNodeRegister.COL_WRITE_ONCE, + TCFNodeRegister.COL_SIDE_EFFECTS, + TCFNodeRegister.COL_VOLATILE, + TCFNodeRegister.COL_FLOAT, + TCFNodeRegister.COL_MNEMONIC + }; + + private static String[] headers = { + "Name", + "Hex", + "Decimal", + "Description", + "Readable", + "Read Once", + "Writable", + "Write Once", + "Side Effects", + "Volatile", + "Float", + "Mnemonic" + }; + + private static String[] cols_ini = { + TCFNodeRegister.COL_NAME, + TCFNodeRegister.COL_HEX_VALUE, + TCFNodeRegister.COL_DEC_VALUE, + TCFNodeRegister.COL_DESCRIPTION, + TCFNodeRegister.COL_MNEMONIC + }; + + public void dispose() { + } + + public String[] getAvailableColumns() { + return cols_all; + } + + public String getHeader(String id) { + for (int i = 0; i < cols_all.length; i++) { + if (id.equals(cols_all[i])) return headers[i]; + } + return null; + } + + public String getId() { + return PRESENTATION_ID; + } + + public ImageDescriptor getImageDescriptor(String id) { + return null; + } + + public String[] getInitialColumns() { + return cols_ini; + } + + public void init(IPresentationContext context) { + } + + public boolean isOptional() { + return false; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java new file mode 100644 index 000000000..f4826d2c3 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java @@ -0,0 +1,351 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.debug.core.commands.IDisconnectHandler; +import org.eclipse.debug.core.commands.IResumeHandler; +import org.eclipse.debug.core.commands.IStepIntoHandler; +import org.eclipse.debug.core.commands.IStepOverHandler; +import org.eclipse.debug.core.commands.IStepReturnHandler; +import org.eclipse.debug.core.commands.ISuspendHandler; +import org.eclipse.debug.core.commands.ITerminateHandler; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.swt.widgets.Display; + +import com.windriver.debug.tcf.core.model.TCFLaunch; +import com.windriver.debug.tcf.ui.commands.DisconnectCommand; +import com.windriver.debug.tcf.ui.commands.ResumeCommand; +import com.windriver.debug.tcf.ui.commands.StepIntoCommand; +import com.windriver.debug.tcf.ui.commands.StepOverCommand; +import com.windriver.debug.tcf.ui.commands.StepReturnCommand; +import com.windriver.debug.tcf.ui.commands.SuspendCommand; +import com.windriver.debug.tcf.ui.commands.TerminateCommand; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.services.IMemory; +import com.windriver.tcf.api.services.IRunControl; + +public class TCFModel implements IElementContentProvider, IElementLabelProvider, + IModelProxyFactory, IColumnPresentationFactory { + + private final Display display; + private final TCFLaunch launch; + private final TCFNode launch_node; + private final Map<IPresentationContext,TCFModelProxy> model_proxies = + new HashMap<IPresentationContext,TCFModelProxy>(); + private final Map<String,TCFNode> id2node = new HashMap<String,TCFNode>(); + private final Map<TCFNode,ModelDelta> deltas = new HashMap<TCFNode,ModelDelta>(); + @SuppressWarnings("unchecked") + private final Map<Class,Object> commands = new HashMap<Class,Object>(); + + private final IMemory.MemoryListener mem_listener = new IMemory.MemoryListener() { + + public void contextAdded(IMemory.MemoryContext[] contexts) { + for (int i = 0; i < contexts.length; i++) { + TCFNode node = getNode(contexts[i].getParentID()); + if (node != null) node.onContextAdded(contexts[i]); + } + fireModelChanged(); + } + + public void contextChanged(IMemory.MemoryContext[] contexts) { + for (int i = 0; i < contexts.length; i++) { + TCFNode node = getNode(contexts[i].getID()); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContextChanged(contexts[i]); + } + } + fireModelChanged(); + } + + public void contextRemoved(String[] context_ids) { + for (int i = 0; i < context_ids.length; i++) { + TCFNode node = getNode(context_ids[i]); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContextRemoved(); + } + } + fireModelChanged(); + } + + public void memoryChanged(String context_id, Number[] addr, long[] size) { + TCFNode node = getNode(context_id); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onMemoryChanged(addr, size); + } + fireModelChanged(); + } + }; + + private final IRunControl.RunControlListener run_listener = new IRunControl.RunControlListener() { + + public void containerResumed(String[] context_ids) { + for (int i = 0; i < context_ids.length; i++) { + TCFNode node = getNode(context_ids[i]); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContainerResumed(); + } + } + fireModelChanged(); + } + + public void containerSuspended(String context, String pc, String reason, + Map<String,Object> params, String[] suspended_ids) { + for (int i = 0; i < suspended_ids.length; i++) { + TCFNode node = getNode(suspended_ids[i]); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContainerSuspended(); + } + } + TCFNode node = getNode(context); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContextSuspended(pc, reason, params); + } + fireModelChanged(); + } + + public void contextAdded(IRunControl.RunControlContext[] contexts) { + for (int i = 0; i < contexts.length; i++) { + TCFNode node = getNode(contexts[i].getParentID()); + if (node != null) node.onContextAdded(contexts[i]); + } + fireModelChanged(); + } + + public void contextChanged(IRunControl.RunControlContext[] contexts) { + for (int i = 0; i < contexts.length; i++) { + TCFNode node = getNode(contexts[i].getID()); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContextChanged(contexts[i]); + } + } + fireModelChanged(); + } + + public void contextException(String context, String msg) { + TCFNode node = getNode(context); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContextException(msg); + } + fireModelChanged(); + } + + public void contextRemoved(String[] context_ids) { + for (int i = 0; i < context_ids.length; i++) { + TCFNode node = getNode(context_ids[i]); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContextRemoved(); + } + } + fireModelChanged(); + } + + public void contextResumed(String context) { + TCFNode node = getNode(context); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContextResumed(); + } + fireModelChanged(); + } + + public void contextSuspended(String context, String pc, String reason, Map<String,Object> params) { + TCFNode node = getNode(context); + if (node instanceof TCFNodeExecContext) { + ((TCFNodeExecContext)node).onContextSuspended(pc, reason, params); + } + fireModelChanged(); + } + }; + + TCFModel(Display display, TCFLaunch launch) { + this.display = display; + this.launch = launch; + launch_node = new TCFNodeLaunch(TCFModel.this); + commands.put(ISuspendHandler.class, new SuspendCommand(this)); + commands.put(IResumeHandler.class, new ResumeCommand(this)); + commands.put(ITerminateHandler.class, new TerminateCommand(this)); + commands.put(IDisconnectHandler.class, new DisconnectCommand(this)); + commands.put(IStepIntoHandler.class, new StepIntoCommand(this)); + commands.put(IStepOverHandler.class, new StepOverCommand(this)); + commands.put(IStepReturnHandler.class, new StepReturnCommand(this)); + } + + @SuppressWarnings("unchecked") + public Object getCommand(Class c) { + Object o = commands.get(c); + assert o == null || c.isInstance(o); + return o; + } + + void onConnected() { + assert Protocol.isDispatchThread(); + IMemory mem = launch.getService(IMemory.class); + if (mem != null) mem.addListener(mem_listener); + IRunControl run = launch.getService(IRunControl.class); + if (run != null) run.addListener(run_listener); + launch_node.invalidateNode(); + launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + fireModelChanged(); + } + + void onDisconnected() { + assert Protocol.isDispatchThread(); + TCFNode[] a = id2node.values().toArray(new TCFNode[id2node.size()]); + for (int i = 0; i < a.length; i++) { + if (!a[i].isDisposed()) a[i].dispose(); + } + launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + fireModelChanged(); + } + + void onProxyInstalled(final TCFModelProxy p) { + Protocol.invokeAndWait(new Runnable() { + public void run() { + model_proxies.put(p.getPresentationContext(), p); + } + }); + } + + void onProxyDisposed(final TCFModelProxy p) { + Protocol.invokeAndWait(new Runnable() { + public void run() { + model_proxies.remove(p.getPresentationContext()); + } + }); + } + + void launchChanged() { + launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + fireModelChanged(); + } + + void dispose() { + } + + void addNode(String id, TCFNode node) { + assert id != null; + assert Protocol.isDispatchThread(); + assert id2node.get(id) == null; + assert !node.isDisposed(); + id2node.put(id, node); + } + + void removeNode(String id) { + assert id != null; + assert Protocol.isDispatchThread(); + id2node.remove(id); + } + + ModelDelta getDelta(TCFNode node) { + return deltas.get(node); + } + + void addDelta(TCFNode node, ModelDelta delta) { + assert deltas.get(node) == null; + deltas.put(node, delta); + } + + void fireModelChanged() { + assert Protocol.isDispatchThread(); + ModelDelta delta = deltas.get(launch_node); + assert (delta == null) == deltas.isEmpty(); + if (delta != null) { + deltas.clear(); + IModelDelta top = delta.getParentDelta(); + for (TCFModelProxy p : model_proxies.values()) p.fireModelChanged(top); + } + } + + public Display getDisplay() { + return display; + } + + public TCFLaunch getLaunch() { + return launch; + } + + public TCFNode getRootNode() { + return launch_node; + } + + public TCFNode getNode(String id) { + if (id == null) return null; + if (id.equals("")) return launch_node; + assert Protocol.isDispatchThread(); + return id2node.get(id); + } + + public void update(IChildrenCountUpdate[] updates) { + for (int i = 0; i < updates.length; i++) { + Object o = updates[i].getElement(); + if (o instanceof TCFLaunch) launch_node.update(updates[i]); + else ((TCFNode)o).update(updates[i]); + } + } + + public void update(IChildrenUpdate[] updates) { + for (int i = 0; i < updates.length; i++) { + Object o = updates[i].getElement(); + if (o instanceof TCFLaunch) launch_node.update(updates[i]); + else ((TCFNode)o).update(updates[i]); + } + } + + public void update(IHasChildrenUpdate[] updates) { + for (int i = 0; i < updates.length; i++) { + Object o = updates[i].getElement(); + if (o instanceof TCFLaunch) launch_node.update(updates[i]); + else ((TCFNode)o).update(updates[i]); + } + } + + public void update(ILabelUpdate[] updates) { + for (int i = 0; i < updates.length; i++) { + Object o = updates[i].getElement(); + assert o != launch_node; + if (o instanceof TCFLaunch) launch_node.update(updates[i]); + else ((TCFNode)o).update(updates[i]); + } + } + + public IModelProxy createModelProxy(Object element, IPresentationContext context) { + return new TCFModelProxy(this); + } + + public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) { + String id = getColumnPresentationId(context, element); + if (id == null) return null; + if (id.equals(TCFColumnPresentationRegister.PRESENTATION_ID)) return new TCFColumnPresentationRegister(); + return null; + } + + public String getColumnPresentationId(IPresentationContext context, Object element) { + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(context.getId())) { + return TCFColumnPresentationRegister.PRESENTATION_ID; + } + return null; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java new file mode 100644 index 000000000..cfb9c9688 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchesListener; +import org.eclipse.swt.widgets.Display; + +import com.windriver.debug.tcf.core.model.TCFLaunch; +import com.windriver.tcf.api.protocol.Protocol; + +public class TCFModelManager { + + private final Display display; + private final Map<TCFLaunch,TCFModel> models = new HashMap<TCFLaunch,TCFModel>(); + + private final TCFLaunch.Listener tcf_launch_listener = new TCFLaunch.Listener() { + + public void onConnected(TCFLaunch launch) { + TCFModel model = models.get(launch); + if (model != null) model.onConnected(); + } + + public void onDisconnected(TCFLaunch launch) { + TCFModel model = models.get(launch); + if (model != null) model.onDisconnected(); + } + }; + + private final ILaunchesListener debug_launch_listener = new ILaunchesListener() { + + public void launchesAdded(final ILaunch[] launches) { + } + + public void launchesChanged(final ILaunch[] launches) { + Protocol.invokeAndWait(new Runnable() { + public void run() { + for (int i = 0; i < launches.length; i++) { + if (launches[i] instanceof TCFLaunch) { + TCFModel model = models.get(launches[i]); + if (model != null) model.launchChanged(); + } + } + } + }); + } + + public void launchesRemoved(final ILaunch[] launches) { + Protocol.invokeAndWait(new Runnable() { + public void run() { + for (int i = 0; i < launches.length; i++) { + if (launches[i] instanceof TCFLaunch) { + TCFModel model = models.remove(launches[i]); + if (model != null) model.dispose(); + } + } + } + }); + } + }; + + public TCFModelManager() { + display = Display.getDefault(); + DebugPlugin.getDefault().getLaunchManager().addLaunchListener(debug_launch_listener); + Protocol.invokeAndWait(new Runnable() { + public void run() { + TCFLaunch.addListener(tcf_launch_listener); + } + }); + } + + public void dispose() { + DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(debug_launch_listener); + Protocol.invokeAndWait(new Runnable() { + public void run() { + TCFLaunch.removeListener(tcf_launch_listener); + for (Iterator<TCFModel> i = models.values().iterator(); i.hasNext();) { + TCFModel model = i.next(); + model.dispose(); + i.remove(); + } + assert models.isEmpty(); + } + }); + } + + public TCFModel getModel(TCFLaunch launch) { + TCFModel model = models.get(launch); + if (model == null) { + model = new TCFModel(display, launch); + models.put(launch, model); + if (launch.getChannel() != null) tcf_launch_listener.onConnected(launch); + } + return model; + } + + public TCFNode getRootNode(TCFLaunch launch) { + return getModel(launch).getRootNode(); + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java new file mode 100644 index 000000000..07e358631 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java @@ -0,0 +1,247 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugModelPresentation; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.debug.ui.IDebugView; +import org.eclipse.debug.ui.IValueDetailListener; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.ISelectionListener; +import org.eclipse.ui.IWindowListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +import com.windriver.debug.tcf.core.model.ITCFBreakpointListener; +import com.windriver.debug.tcf.core.model.TCFBreakpoint; +import com.windriver.debug.tcf.core.model.TCFBreakpointsStatus; +import com.windriver.debug.tcf.core.model.TCFLaunch; +import com.windriver.tcf.api.protocol.IChannel; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.services.IBreakpoints; + +public class TCFModelPresentation implements IDebugModelPresentation { + + private final Collection<ILabelProviderListener> listeners = new HashSet<ILabelProviderListener>(); + + private IWorkbenchWindow active_window; + private TCFLaunch launch_selection; + + private final TCFLaunch.Listener launch_listener = new TCFLaunch.Listener() { + + public void onConnected(TCFLaunch launch) { + updateLaunchSelection(); + } + + public void onDisconnected(TCFLaunch launch) { + updateLaunchSelection(); + } + }; + + private final ISelectionListener selection_listener = new ISelectionListener() { + + public void selectionChanged(IWorkbenchPart part, ISelection selection) { + updateLaunchSelection(); + } + }; + + private final IWindowListener window_listener = new IWindowListener() { + + public void windowActivated(IWorkbenchWindow window) { + if (active_window != null) { + active_window.getSelectionService().removeSelectionListener( + IDebugUIConstants.ID_DEBUG_VIEW, selection_listener); + active_window = null; + } + window.getSelectionService().addSelectionListener( + IDebugUIConstants.ID_DEBUG_VIEW, selection_listener); + active_window = window; + updateLaunchSelection(); + } + + public void windowClosed(IWorkbenchWindow window) { + if (window == active_window) { + active_window.getSelectionService().removeSelectionListener( + IDebugUIConstants.ID_DEBUG_VIEW, selection_listener); + active_window = null; + } + } + + public void windowDeactivated(IWorkbenchWindow window) { + } + + public void windowOpened(IWorkbenchWindow window) { + } + }; + + private final ITCFBreakpointListener breakpoint_status_listener = new ITCFBreakpointListener() { + + public void breakpointStatusChanged(String id) { + refreshBreakpointView(); + } + }; + + public TCFModelPresentation() { + Protocol.invokeAndWait(new Runnable() { + public void run() { + TCFLaunch.addListener(launch_listener); + } + }); + PlatformUI.getWorkbench().addWindowListener(window_listener); + IWorkbenchWindow w = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (w != null) window_listener.windowActivated(w); + } + + private void updateLaunchSelection() { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + TCFLaunch launch = null; + IAdaptable adaptable = DebugUITools.getDebugContext(); + if (adaptable != null) { + ILaunch x = (ILaunch)adaptable.getAdapter(ILaunch.class); + if (x instanceof TCFLaunch) { + final TCFLaunch l = (TCFLaunch)x; + final boolean[] b = new boolean[1]; + Protocol.invokeAndWait(new Runnable() { + public void run() { + IChannel channel = l.getChannel(); + b[0] = channel != null && channel.getState() == IChannel.STATE_OPEN; + } + }); + if (b[0]) launch = l; + } + } + if (launch_selection != launch) { + setBreakpointStatusListener(launch_selection, launch); + launch_selection = launch; + refreshBreakpointView(); + } + } + }); + } + + private void refreshBreakpointView() { + Display.getDefault().asyncExec(new Runnable() { + public void run() { + if (active_window != null) { + final IDebugView view = (IDebugView)active_window.getActivePage().findView( + IDebugUIConstants.ID_BREAKPOINT_VIEW); + if (view != null) { + view.getViewer().refresh(); + } + } + } + }); + } + + private void setBreakpointStatusListener(final TCFLaunch prev, final TCFLaunch next) { + Protocol.invokeAndWait(new Runnable() { + public void run() { + if (prev != null && prev.getBreakpointsStatus() != null) { + prev.getBreakpointsStatus().removeListener(breakpoint_status_listener); + } + if (next != null && next.getBreakpointsStatus() != null) { + next.getBreakpointsStatus().addListener(breakpoint_status_listener); + } + } + }); + } + + public void addListener(ILabelProviderListener listener) { + listeners.add(listener); + } + + public void removeListener(ILabelProviderListener listener) { + listeners.remove(listener); + } + + public void dispose() { + if (launch_selection != null) { + setBreakpointStatusListener(launch_selection, null); + launch_selection = null; + } + if (active_window != null) { + active_window.getSelectionService().removeSelectionListener( + IDebugUIConstants.ID_DEBUG_VIEW, selection_listener); + active_window = null; + } + PlatformUI.getWorkbench().removeWindowListener(window_listener); + Protocol.invokeAndWait(new Runnable() { + public void run() { + TCFLaunch.removeListener(launch_listener); + } + }); + } + + public void computeDetail(IValue value, IValueDetailListener listener) { + } + + public Image getImage(Object element) { + return null; + } + + public String getText(Object element) { + if (element instanceof TCFBreakpoint) { + final TCFBreakpoint breakpoint = (TCFBreakpoint)element; + final TCFLaunch launch = launch_selection; + final String[] text = new String[1]; + text[0] = breakpoint.getText(); + if (launch != null) { + Protocol.invokeAndWait(new Runnable() { + public void run() { + TCFBreakpointsStatus bs = launch.getBreakpointsStatus(); + if (bs != null) { + Map<String,Object> map = bs.getStatus(breakpoint); + if (map != null) { + String status = null; + String error = (String)map.get(IBreakpoints.STATUS_ERROR); + Object planted = map.get(IBreakpoints.STATUS_PLANTED); + if (error != null) status = error; + else if (planted != null) status = "Planted"; + if (status != null) text[0] += " (" + status + ")"; + } + } + } + }); + } + return text[0]; + } + return null; + } + + public void setAttribute(String attribute, Object value) { + } + + public boolean isLabelProperty(Object element, String property) { + return true; + } + + public String getEditorId(IEditorInput input, Object element) { + return null; + } + + public IEditorInput getEditorInput(Object element) { + return null; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java new file mode 100644 index 000000000..dbdae8822 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy; +import org.eclipse.jface.viewers.Viewer; + +public class TCFModelProxy extends AbstractModelProxy implements IModelProxy { + + private final TCFModel model; + + TCFModelProxy(TCFModel model) { + this.model = model; + } + + public void installed(Viewer viewer) { + super.installed(viewer); + model.onProxyInstalled(this); + } + + public void dispose() { + model.onProxyDisposed(this); + super.dispose(); + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java new file mode 100644 index 000000000..6c07354ea --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.jface.viewers.ISelection; + +public class TCFModelSelectionPolicy implements IModelSelectionPolicy { + + public boolean contains(ISelection selection, IPresentationContext context) { + // TODO Auto-generated method stub + return false; + } + + public boolean isSticky(ISelection selection, IPresentationContext context) { + // TODO Auto-generated method stub + return false; + } + + public boolean overrides(ISelection existing, ISelection candidate, + IPresentationContext context) { + // TODO Auto-generated method stub + return false; + } + + public ISelection replaceInvalidSelection(ISelection invalidSelection, + ISelection newSelection) { + // TODO Auto-generated method stub + return null; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java new file mode 100644 index 000000000..c213e0c2d --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java @@ -0,0 +1,451 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.model.IMemoryBlock; +import org.eclipse.debug.core.model.IMemoryBlockExtension; +import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.RGB; +import org.osgi.framework.Bundle; + +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.services.IMemory; +import com.windriver.tcf.api.services.IRunControl; + +/** + * TCFNode is base class for all TCF debug model elements. + */ +public class TCFNode extends PlatformObject +implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> { + + protected final String id; + protected final TCFNode parent; + protected final TCFModel model; + + protected boolean disposed; + + protected TCFNode(TCFNode parent, String id) { + assert Protocol.isDispatchThread(); + this.parent = parent; + this.id = id; + model = parent.model; + } + + protected TCFNode(TCFModel model) { + id = null; + parent = null; + this.model = model; + } + + /** + * Dispose this node. The node is removed from the model. + */ + void dispose() { + assert !disposed; + if (parent != null) parent.dispose(id); + model.removeNode(id); + disposed = true; + } + + /** + * A child node is being disposed. + * The child should be removed from this node children lists. + */ + void dispose(String id) { + } + + /** + * Check if node is disposed. + * @return true if disposed. + */ + public final boolean isDisposed() { + return disposed; + } + + @SuppressWarnings("unchecked") + public Object getAdapter(Class adapter) { + if (adapter == ILaunch.class) return model.getLaunch(); + if (adapter == IModelProxyFactory.class) return model; + if (adapter == IElementLabelProvider.class) return model; + if (adapter == IElementContentProvider.class) return model; + if (adapter == IColumnPresentationFactory.class) return model; + Object o = model.getCommand(adapter); + if (o != null) return o; + //System.err.println(adapter.getName()); + return super.getAdapter(adapter); + } + + public final TCFNode getParent() { + assert Protocol.isDispatchThread(); + return parent; + } + + public IRunControl.RunControlContext getRunContext() { + return null; + } + + public IMemory.MemoryContext getMemoryContext() { + return null; + } + + public boolean isRunning() { + return false; + } + + public boolean isSuspended() { + return false; + } + + /** + * Return address of this node. + * For executable contexts and stack frames address is current PC. + * @return + */ + public String getAddress() { + return null; + } + + /** + * Retrieve children count for a presentation context. + * @param result - children count update request. + */ + final void update(final IChildrenCountUpdate result) { + new TCFRunnable(model.getDisplay(), result) { + public void run() { + if (!disposed && model.getLaunch().getChannel() != null) { + if (!validateNode(this)) return; + getData(result); + } + else { + result.setChildCount(0); + } + result.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + /** + * Retrieve children for a presentation context. + * @param result - children update request. + */ + final void update(final IChildrenUpdate result) { + new TCFRunnable(model.getDisplay(), result) { + public void run() { + if (!disposed && model.getLaunch().getChannel() != null) { + if (!validateNode(this)) return; + getData(result); + } + result.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + /** + * Check if node has children in a presentation context. + * @param result - "has children" update request. + */ + final void update(final IHasChildrenUpdate result) { + new TCFRunnable(model.getDisplay(), result) { + public void run() { + if (!disposed && model.getLaunch().getChannel() != null) { + if (!validateNode(this)) return; + getData(result); + } + else { + result.setHasChilren(false); + } + result.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + /** + * Retrieve node label for a presentation context. + * @param result - label update request. + */ + final void update(final ILabelUpdate result) { + new TCFRunnable(model.getDisplay(), result) { + public void run() { + if (!disposed) { + if (!validateNode(this)) return; + if (node_error != null) { + result.setBackground(new RGB(255, 0, 0), 0); + result.setLabel(node_error.getClass().getName() + + ": " + node_error.getMessage(), 0); + } + else { + getData(result); + } + } + else { + result.setLabel("[Disposed]", 0); + } + result.setStatus(Status.OK_STATUS); + done(); + } + }; + } + + /** + * Retrieve children count for a presentation context. + * The node is validated before calling this method, + * so the method should return cached data. + * The method is always called on TCF dispatch thread. + * @param result - children count update request. + */ + protected void getData(IChildrenCountUpdate result) { + result.setChildCount(0); + } + + /** + * Retrieve children for a presentation context. + * The node is validated before calling this method, + * so the method should return cached data. + * The method is always called on TCF dispatch thread. + * @param result - children update request. + */ + protected void getData(IChildrenUpdate result) { + } + + /** + * Check if the node has children in a presentation context. + * The node is validated before calling this method, + * so the method should return cached data. + * The method is always called on TCF dispatch thread. + * @param result - "has children" update request. + */ + protected void getData(IHasChildrenUpdate result) { + result.setHasChilren(false); + } + + /** + * Retrieve node label for a presentation context. + * The node is validated before calling this method, + * so the method should return cached data. + * The method is always called on TCF dispatch thread. + * @param result - label update request. + */ + protected void getData(ILabelUpdate result) { + result.setImageDescriptor(getImageDescriptor(getImageName()), 0); + result.setLabel(id, 0); + } + + /** + * Create ModelDelta for changes in this node. + * @param flags - description of what has changed: CF_CONTEXT, CF_CHILDREN or CF_ALL. + * @return - ModelDelta that describes node changes. + */ + ModelDelta makeModelDelta(int flags) { + int count = -1; + //if (node_valid == CF_ALL) count = children.size(); + ModelDelta delta = model.getDelta(this); + int index = -1; + /* + if (parent.node_valid == CF_ALL) { + index = 0; + for (Iterator<TCFNode> i = parent.children.values().iterator(); i.hasNext();) { + if (i.next() == this) break; + index++; + } + } + */ + if (delta == null || delta.getChildCount() != count || delta.getIndex() != index) { + ModelDelta parent_delta = parent.makeModelDelta(IModelDelta.NO_CHANGE); + delta = parent_delta.addNode(this, index, flags, count); + model.addDelta(this, delta); + } + else { + delta.setFlags(delta.getFlags() | flags); + } + return delta; + } + + void onContextAdded(IRunControl.RunControlContext context) { + assert !disposed; + // TODO: Bug in Eclipse: IModelDelta.INSERTED fails if this is root node + invalidateNode(CF_CHILDREN); + makeModelDelta(IModelDelta.CONTENT); + } + + void onContextAdded(IMemory.MemoryContext context) { + assert !disposed; + // TODO: Bug in Eclipse: IModelDelta.INSERTED fails if this is root node + invalidateNode(CF_CHILDREN); + makeModelDelta(IModelDelta.CONTENT); + } + + /*--------------------------------------------------------------------------------------*/ + /* Node data retrieval state machine */ + + protected static final int + CF_CHILDREN = 0x0001, + CF_CONTEXT = 0x0002, + CF_ALL = CF_CHILDREN | CF_CONTEXT; + + protected int node_valid; + protected Throwable node_error; + protected IToken data_command; + protected final Collection<TCFRunnable> wait_list = new ArrayList<TCFRunnable>(); + + /** + * Invalidate the node - flush all cached data. + */ + public void invalidateNode() { + invalidateNode(CF_ALL); + } + + protected void invalidateNode(int flags) { + // flags - set of CF_* + + // cancel current data retrieval command + if (data_command != null) { + data_command.cancel(); + data_command = null; + } + + // cancel waiting monitors + if (!wait_list.isEmpty()) { + TCFRunnable[] arr = wait_list.toArray(new TCFRunnable[wait_list.size()]); + for (TCFRunnable r : arr) r.cancel(); + wait_list.clear(); + } + + if (flags == CF_ALL) { + node_error = null; + } + + node_valid &= ~flags; + } + + /** + * Validate node - retrieve and put into a cache missing data from remote peer. + * Validation is done asynchronously. + * @param done - call back, it is called when validation is done. + * @return true if the node is valid, false if validation is started. + */ + public boolean validateNode(TCFRunnable done) { + assert Protocol.isDispatchThread(); + assert (node_valid & ~CF_ALL) == 0; + if (data_command != null) { + if (done != null) wait_list.add(done); + return false; + } + else if (model.getLaunch().getChannel() == null) { + node_error = null; + node_valid = CF_ALL; + } + else { + if ((node_valid & CF_CONTEXT) == 0 && !validateContext(done)) return false; + if ((node_valid & CF_CHILDREN) == 0 && !validateChildren(done)) return false; + } + assert node_valid == CF_ALL; + if (!wait_list.isEmpty()) { + Runnable[] arr = wait_list.toArray(new Runnable[wait_list.size()]); + wait_list.clear(); + for (int i = 0; i < arr.length; i++) arr[i].run(); + } + return true; + } + + protected boolean validateContext(TCFRunnable done) { + node_valid |= CF_CONTEXT; + return true; + } + + protected boolean validateChildren(TCFRunnable done) { + node_valid |= CF_CHILDREN; + return true; + } + + /*--------------------------------------------------------------------------------------*/ + /* Memory Block Retrieval */ + + public IMemoryBlockExtension getExtendedMemoryBlock(String addr, Object ctx) throws DebugException { + assert ctx == this; + return getMemoryBlock(addr, 0); + } + + public IMemoryBlock getMemoryBlock(long addr, long length) throws DebugException { + return getMemoryBlock(Long.toString(addr), length); + } + + public boolean supportsStorageRetrieval() { + return getMemoryContext() != null; + } + + private IMemoryBlockExtension getMemoryBlock(String addr, long length) throws DebugException { + assert !Protocol.isDispatchThread(); + // TODO: MemoryBlock + return null; + } + + /*--------------------------------------------------------------------------------------*/ + /* Misc */ + + private static final Map<String,ImageDescriptor> image_cache = new HashMap<String,ImageDescriptor>(); + + static ImageDescriptor getImageDescriptor(String name) { + if (name == null) return null; + ImageDescriptor descriptor = image_cache.get(name); + if (descriptor == null) { + descriptor = ImageDescriptor.getMissingImageDescriptor(); + Bundle bundle = Platform.getBundle("org.eclipse.debug.ui"); + if (bundle != null){ + URL url = FileLocator.find(bundle, new Path(name), null); + descriptor = ImageDescriptor.createFromURL(url); + } + image_cache.put(name, descriptor); + } + return descriptor; + } + + protected String getImageName() { + return null; + } + + public int compareTo(TCFNode n) { + return id.compareTo(n.id); + } + + public String toString() { + String s = "[" + Integer.toHexString(hashCode()) + "] " + id; + if (disposed) s += ", disposed"; + return s; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java new file mode 100644 index 000000000..996391ce0 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java @@ -0,0 +1,487 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import java.util.Arrays; +import java.util.Map; + +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; +import org.eclipse.debug.ui.IDebugUIConstants; + +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.services.IMemory; +import com.windriver.tcf.api.services.IRunControl; + +public class TCFNodeExecContext extends TCFNode { + + private final TCFChildren children_exec; + private final TCFChildren children_stack; + private final TCFChildren children_regs; + + private IMemory.MemoryContext mem_context; + private IRunControl.RunControlContext run_context; + + private boolean suspended; + private String suspended_pc; + private String suspended_reason; + @SuppressWarnings("unused") + private Map<String,Object> suspended_params; + private boolean running; + private boolean terminated; + @SuppressWarnings("unused") + private String exception_msg; + + private boolean valid_mem_ctx; + private boolean valid_run_ctx; + private boolean valid_state; + + TCFNodeExecContext(TCFNode parent, String id) { + super(parent, id); + children_exec = new TCFChildrenExecContext(this); + children_regs = new TCFChildrenRegisters(this); + children_stack = new TCFChildrenStackTrace(this, children_regs); + } + + @Override + void dispose() { + children_exec.dispose(); + children_stack.dispose(); + children_regs.dispose(); + super.dispose(); + } + + @Override + void dispose(String id) { + children_exec.dispose(id); + children_stack.dispose(id); + children_regs.dispose(id); + } + + @Override + public IRunControl.RunControlContext getRunContext() { + assert Protocol.isDispatchThread(); + return run_context; + } + + @Override + public IMemory.MemoryContext getMemoryContext() { + assert Protocol.isDispatchThread(); + return mem_context; + } + + @Override + public boolean isRunning() { + assert Protocol.isDispatchThread(); + return running; + } + + @Override + public boolean isSuspended() { + assert Protocol.isDispatchThread(); + return suspended; + } + + @Override + public String getAddress() { + assert Protocol.isDispatchThread(); + return suspended_pc; + } + + @Override + protected void getData(IChildrenCountUpdate result) { + if (run_context != null && run_context.hasState()) { + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { + result.setChildCount(children_regs.size()); + } + else { + result.setChildCount(children_stack.size()); + } + } + else { + result.setChildCount(children_exec.size()); + } + } + + @Override + protected void getData(IChildrenUpdate result) { + int offset = 0; + TCFNode[] arr = null; + if (run_context != null && run_context.hasState()) { + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { + arr = children_regs.toArray(); + } + else { + arr = children_stack.toArray(); + } + } + else { + arr = children_exec.toArray(); + } + Arrays.sort(arr); + for (TCFNode n : arr) { + if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) { + result.setChild(n, offset); + } + offset++; + } + } + + @Override + protected void getData(IHasChildrenUpdate result) { + if (run_context != null && run_context.hasState()) { + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { + result.setHasChilren(children_regs.size() > 0); + } + else { + result.setHasChilren(children_stack.size() > 0); + } + } + else { + result.setHasChilren(children_exec.size() > 0); + } + } + + @Override + protected void getData(ILabelUpdate result) { + result.setImageDescriptor(getImageDescriptor(getImageName()), 0); + String label = id; + if (run_context != null) { + if (run_context.hasState()) { + if (running) { + label += " (Running)"; + } + else if (suspended) { + if (suspended_reason != null) { + label += " (" + suspended_reason + ")"; + } + else { + label += " (Suspended)"; + } + } + } + String file = (String)run_context.getProperties().get("File"); + if (file != null) label += " " + file; + } + result.setLabel(label, 0); + } + + @Override + ModelDelta makeModelDelta(int flags) { + if (run_context != null && run_context.isContainer()) flags |= IModelDelta.STATE; + return super.makeModelDelta(flags); + } + + @Override + void onContextAdded(IRunControl.RunControlContext context) { + assert !disposed; + if (node_valid == CF_ALL) { + String id = context.getID(); + TCFNodeExecContext n = (TCFNodeExecContext)children_exec.children.get(id); + if (n == null) { + n = new TCFNodeExecContext(this, id); + n.run_context = context; + n.valid_run_ctx = true; + children_exec.children.put(id, n); + model.addNode(id, n); + n.makeModelDelta(IModelDelta.INSERTED); + } + else { + n.run_context = context; + n.makeModelDelta(IModelDelta.STATE); + } + } + else { + invalidateNode(CF_CHILDREN); + makeModelDelta(IModelDelta.CONTENT); + } + } + + void onContextChanged(IRunControl.RunControlContext context) { + assert !disposed; + run_context = context; + invalidateNode(CF_CHILDREN); + makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + } + + @Override + void onContextAdded(IMemory.MemoryContext context) { + assert !disposed; + if (node_valid == CF_ALL) { + String id = context.getID(); + TCFNodeExecContext n = (TCFNodeExecContext)children_exec.children.get(id); + if (n == null) { + n = new TCFNodeExecContext(this, id); + n.mem_context = context; + n.valid_mem_ctx = true; + children_exec.children.put(id, n); + model.addNode(id, n); + n.makeModelDelta(IModelDelta.INSERTED); + } + else { + n.mem_context = context; + n.makeModelDelta(IModelDelta.STATE); + } + } + else { + invalidateNode(CF_CHILDREN); + makeModelDelta(IModelDelta.CONTENT); + } + } + + void onContextChanged(IMemory.MemoryContext context) { + assert !disposed; + mem_context = context; + invalidateNode(CF_CHILDREN); + makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + } + + void onContextRemoved() { + assert !disposed; + dispose(); + if (parent.node_valid == CF_ALL) { + makeModelDelta(IModelDelta.REMOVED); + } + else { + parent.invalidateNode(CF_CHILDREN); + parent.makeModelDelta(IModelDelta.CONTENT); + } + } + + void onContainerSuspended() { + assert !disposed; + if (run_context == null) return; + if (!run_context.hasState()) return; + suspended = false; + running = false; + valid_state = false; + invalidateNode(CF_CHILDREN); + suspended = true; + makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + } + + void onContainerResumed() { + assert !disposed; + if (run_context == null) return; + if (!run_context.hasState()) return; + suspended = false; + running = false; + valid_state = false; + invalidateNode(CF_CHILDREN); + suspended = false; + makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + } + + void onContextSuspended(String pc, String reason, Map<String,Object> params) { + assert !disposed; + if (run_context == null) return; + if (!run_context.hasState()) return; + invalidateNode(CF_CHILDREN); + suspended = true; + suspended_pc = pc; + suspended_reason = reason; + suspended_params = params; + running = false; + valid_state = true; + makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + } + + void onContextResumed() { + assert !disposed; + if (run_context == null) return; + if (!run_context.hasState()) return; + invalidateNode(CF_CHILDREN); + exception_msg = null; + terminated = false; + suspended = false; + suspended_pc = null; + suspended_reason = null; + suspended_params = null; + running = true; + valid_state = true; + makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT); + } + + void onContextException(String msg) { + assert !disposed; + exception_msg = msg; + makeModelDelta(IModelDelta.STATE); + } + + void onMemoryChanged(Number[] addr, long[] size) { + assert !disposed; + } + + @Override + protected void invalidateNode(int flags) { + super.invalidateNode(flags); + if ((flags & CF_CONTEXT) != 0) { + valid_mem_ctx = false; + valid_run_ctx = false; + valid_state = false; + running = false; + suspended = false; + } + if ((flags & CF_CHILDREN) != 0) { + children_exec.invalidate(); + children_stack.invalidate(); + children_regs.invalidate(); + } + } + + @Override + protected boolean validateContext(TCFRunnable done) { + if (!valid_mem_ctx && !validateMemoryContext(done)) return false; + if (!valid_run_ctx && !validateRunControlContext(done)) return false; + if (!valid_state && !validateRunControlState(done)) return false; + node_valid |= CF_CONTEXT; + return true; + } + + @Override + protected boolean validateChildren(TCFRunnable done) { + if (!children_stack.valid && !children_stack.validate(done)) return false; + if (!children_regs.valid && !children_regs.validate(done)) return false; + if (!children_exec.valid && !children_exec.validate(done)) return false; + node_valid |= CF_CHILDREN; + return true; + } + + private boolean validateMemoryContext(TCFRunnable done) { + assert data_command == null; + IMemory mem = model.getLaunch().getService(IMemory.class); + if (mem == null) { + valid_mem_ctx = true; + return true; + } + if (done != null) wait_list.add(done); + data_command = mem.getContext(id, new IMemory.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, IMemory.MemoryContext context) { + if (data_command != token) return; + data_command = null; + if (error != null) { + node_error = error; + } + else { + mem_context = context; + } + valid_mem_ctx = true; + validateNode(null); + } + }); + return false; + } + + private boolean validateRunControlContext(TCFRunnable done) { + assert data_command == null; + IRunControl run = model.getLaunch().getService(IRunControl.class); + if (run == null) { + valid_run_ctx = true; + return true; + } + if (done != null) wait_list.add(done); + data_command = run.getContext(id, new IRunControl.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, IRunControl.RunControlContext context) { + if (data_command != token) return; + data_command = null; + if (error != null) { + node_error = error; + } + else { + run_context = context; + } + valid_run_ctx = true; + validateNode(null); + } + }); + return false; + } + + private boolean validateRunControlState(TCFRunnable done) { + assert data_command == null; + if (node_error != null || run_context == null || !run_context.hasState()) { + suspended = false; + suspended_pc = null; + suspended_reason = null; + suspended_params = null; + running = false; + valid_state = true; + return true; + } + if (done != null) wait_list.add(done); + data_command = run_context.getState(new IRunControl.DoneGetState() { + public void doneGetState(IToken token, Exception error, boolean suspend, String pc, String reason, Map<String,Object> params) { + if (token != data_command) return; + data_command = null; + if (error != null) { + suspended = false; + suspended_pc = null; + suspended_reason = null; + suspended_params = null; + node_error = error; + running = false; + } + else { + suspended = suspend; + if (suspend) { + suspended_pc = pc; + suspended_reason = reason; + suspended_params = params; + } + else { + suspended_pc = null; + suspended_reason = null; + suspended_params = null; + } + running = !suspend; + } + valid_state = true; + validateNode(null); + } + }); + return false; + } + + private boolean hasSuspendedChildren() { + for (TCFNode n : children_exec.children.values()) { + if (n instanceof TCFNodeExecContext) { + TCFNodeExecContext e = (TCFNodeExecContext)n; + if (e.run_context != null) { + if (e.run_context.hasState() && e.suspended) return true; + if (e.run_context.isContainer() && e.hasSuspendedChildren()) return true; + } + } + } + return false; + } + + @Override + protected String getImageName() { + if (run_context != null && run_context.hasState()) { + // Thread + if (terminated) return "icons/full/obj16/threadt_obj.gif"; + if (suspended) return "icons/full/obj16/threads_obj.gif"; + return "icons/full/obj16/thread_obj.gif"; + } + else if (run_context != null) { + // Thread container (process) + if (terminated) return "icons/full/obj16/debugtt_obj.gif"; + if (hasSuspendedChildren()) return "icons/full/obj16/debugts_obj.gif"; + return "icons/full/obj16/debugt_obj.gif"; + } + return super.getImageName(); + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java new file mode 100644 index 000000000..b800e2cbe --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import java.util.Arrays; + +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta; +import org.eclipse.swt.graphics.RGB; + +import com.windriver.debug.tcf.core.model.TCFLaunch; + +public class TCFNodeLaunch extends TCFNode { + + private final TCFChildren children; + + TCFNodeLaunch(TCFModel model) { + super(model); + children = new TCFChildrenExecContext(this); + } + + @Override + void dispose() { + children.dispose(); + super.dispose(); + } + + @Override + void dispose(String id) { + children.dispose(id); + } + + @Override + protected void getData(IChildrenCountUpdate result) { + result.setChildCount(children.size()); + } + + @Override + protected void getData(IChildrenUpdate result) { + int offset = 0; + TCFNode[] arr = children.toArray(); + Arrays.sort(arr); + for (TCFNode n : arr) { + if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) { + result.setChild(n, offset); + } + offset++; + } + } + + @Override + protected void getData(IHasChildrenUpdate result) { + result.setHasChilren(children.size() > 0); + } + + @Override + protected void getData(ILabelUpdate result) { + result.setImageDescriptor(getImageDescriptor(getImageName()), 0); + String label = id; + TCFLaunch launch = model.getLaunch(); + String status = ""; + if (launch.isConnecting()) status = "Connecting"; + else if (launch.isDisconnected()) status = "Disconnected"; + else if (launch.isTerminated()) status = "Terminated"; + Throwable error = launch.getError(); + if (error != null) { + status += " - " + error; + result.setForeground(new RGB(255, 0, 0), 0); + } + if (status.length() > 0) status = " (" + status + ")"; + label = launch.getLaunchConfiguration().getName() + status; + result.setLabel(label, 0); + } + + @Override + ModelDelta makeModelDelta(int flags) { + int count = -1; + //if (node_valid == CF_ALL) count = children.size(); + ModelDelta delta = model.getDelta(this); + if (delta == null) { + delta = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE); + delta = delta.addNode(model.getLaunch(), -1, flags, count); + model.addDelta(this, delta); + } + else { + assert delta.getChildCount() == count; + delta.setFlags(delta.getFlags() | flags); + } + return delta; + } + + @Override + protected void invalidateNode(int flags) { + super.invalidateNode(flags); + if ((flags & CF_CHILDREN) != 0) { + children.invalidate(); + } + } + + @Override + protected boolean validateChildren(TCFRunnable done) { + if (!children.valid && !children.validate(done)) return false; + node_valid |= CF_CHILDREN; + return true; + } + + @Override + protected String getImageName() { + return "icons/full/obj16/ldebug_obj.gif"; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java new file mode 100644 index 000000000..9309c1bd9 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; + +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.services.IRegisters; + +// TODO: hierarchical registers +public class TCFNodeRegister extends TCFNode { + + /** + * Presentation column IDs. + */ + public static final String + COL_NAME = "Name", + COL_HEX_VALUE = "HexValue", + COL_DEC_VALUE = "DecValue", + COL_DESCRIPTION = "Description", + COL_READBLE = "Readable", + COL_READ_ONCE = "ReadOnce", + COL_WRITEABLE = "Writeable", + COL_WRITE_ONCE = "WriteOnce", + COL_SIDE_EFFECTS = "SideEffects", + COL_VOLATILE = "Volatile", + COL_FLOAT = "Float", + COL_MNEMONIC = "Menimonic"; + + + private IRegisters.RegistersContext context; + private String hex_value; + private String dec_value; + private Number num_value; + private boolean valid_context; + private boolean valid_hex_value; + private boolean valid_dec_value; + + TCFNodeRegister(TCFNode parent, String id) { + super(parent, id); + } + + @Override + protected void getData(ILabelUpdate result) { + result.setImageDescriptor(getImageDescriptor(getImageName()), 0); + if (context != null) { + String[] cols = result.getColumnIds(); + if (cols == null) { + result.setLabel(context.getName() + " = " + hex_value, 0); + } + else { + for (int i = 0; i < cols.length; i++) { + String c = cols[i]; + if (c.equals(COL_NAME)) result.setLabel(context.getName(), i); + else if (c.equals(COL_HEX_VALUE)) result.setLabel(hex_value, i); + else if (c.equals(COL_DEC_VALUE)) result.setLabel(dec_value, i); + else if (c.equals(COL_DESCRIPTION)) result.setLabel(context.getDescription(), i); + else if (c.equals(COL_READBLE)) result.setLabel(bool(context.isReadable()), i); + else if (c.equals(COL_READ_ONCE)) result.setLabel(bool(context.isReadOnce()), i); + else if (c.equals(COL_WRITEABLE)) result.setLabel(bool(context.isWriteable()), i); + else if (c.equals(COL_WRITE_ONCE)) result.setLabel(bool(context.isWriteOnce()), i); + else if (c.equals(COL_SIDE_EFFECTS)) result.setLabel(bool(context.hasSideEffects()), i); + else if (c.equals(COL_VOLATILE)) result.setLabel(bool(context.isVolatile()), i); + else if (c.equals(COL_FLOAT)) result.setLabel(bool(context.isFloat()), i); + else if (c.equals(COL_MNEMONIC)) result.setLabel(getMnemonic(), i); + } + } + } + else { + result.setLabel(id, 0); + } + } + + private String bool(boolean b) { + return b ? "yes" : "no"; + } + + private String getMnemonic() { + if (num_value != null) { + IRegisters.NamedValue[] arr = context.getNamedValues(); + if (arr != null) { + if (context.isFloat()) { + for (IRegisters.NamedValue n : arr) { + if (n.getValue().doubleValue() == num_value.doubleValue()) return n.getName(); + } + } + else { + for (IRegisters.NamedValue n : arr) { + if (n.getValue().longValue() == num_value.longValue()) return n.getName(); + } + } + } + } + return ""; + } + + @Override + protected void invalidateNode(int flags) { + super.invalidateNode(flags); + if ((flags & CF_CONTEXT) != 0) { + valid_context = false; + valid_hex_value = false; + valid_dec_value = false; + hex_value = null; + dec_value = null; + num_value = null; + } + } + + @Override + protected boolean validateContext(TCFRunnable done) { + if (!valid_context && !validateRegisterContext(done)) return false; + if (!valid_hex_value && !validateRegisterHexValue(done)) return false; + if (!valid_dec_value && !validateRegisterDecValue(done)) return false; + node_valid |= CF_CONTEXT; + return true; + } + + private boolean validateRegisterContext(TCFRunnable done) { + assert data_command == null; + IRegisters regs = model.getLaunch().getService(IRegisters.class); + if (done != null) wait_list.add(done); + data_command = regs.getContext(id, new IRegisters.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, IRegisters.RegistersContext context) { + if (data_command != token) return; + data_command = null; + if (error != null) { + node_error = error; + } + else { + TCFNodeRegister.this.context = context; + } + valid_context = true; + validateNode(null); + } + }); + return false; + } + + private boolean validateRegisterHexValue(TCFRunnable done) { + assert data_command == null; + if (done != null) wait_list.add(done); + String[] fmts = context.getAvailableFormats(); + String fmt = null; + for (String s : fmts) { + if (s.equals(IRegisters.FORMAT_HEX)) fmt = s; + } + if (fmt == null) { + valid_hex_value = true; + return true; + } + data_command = context.get(fmt, new IRegisters.DoneGet() { + public void doneGet(IToken token, Exception error, String value) { + if (data_command != token) return; + data_command = null; + if (error != null) { + node_error = error; + } + else { + hex_value = value; + } + valid_hex_value = true; + if (!context.isFloat()) num_value = Long.valueOf(value, 16); + validateNode(null); + } + }); + return false; + } + + private boolean validateRegisterDecValue(TCFRunnable done) { + assert data_command == null; + if (done != null) wait_list.add(done); + String[] fmts = context.getAvailableFormats(); + String fmt = null; + for (String s : fmts) { + if (s.equals(IRegisters.FORMAT_DECIMAL)) fmt = s; + } + if (fmt == null) { + valid_dec_value = true; + return true; + } + data_command = context.get(fmt, new IRegisters.DoneGet() { + public void doneGet(IToken token, Exception error, String value) { + if (data_command != token) return; + data_command = null; + if (error != null) { + node_error = error; + } + else { + dec_value = value; + } + valid_dec_value = true; + if (!context.isFloat()) num_value = Long.valueOf(value, 10); + else num_value = Double.valueOf(value); + validateNode(null); + } + }); + return false; + } + + @Override + protected String getImageName() { + return "icons/full/obj16/genericregister_obj.gif"; + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java new file mode 100644 index 000000000..91683da5e --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java @@ -0,0 +1,258 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import java.math.BigInteger; +import java.util.Arrays; + +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.ui.IDebugUIConstants; + +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.services.ILineNumbers; +import com.windriver.tcf.api.services.IMemory; +import com.windriver.tcf.api.services.IRunControl; +import com.windriver.tcf.api.services.IStackTrace; +import com.windriver.tcf.api.services.ILineNumbers.CodeArea; + +public class TCFNodeStackFrame extends TCFNode { + + private IStackTrace.StackTraceContext stack_trace_context; + private ILineNumbers.CodeArea code_area; + + private final int frame_no; + private final TCFChildren children_regs; + + TCFNodeStackFrame(TCFNode parent, String id, TCFChildren children_regs) { + super(parent, id); + this.frame_no = 0; + this.children_regs = children_regs; + } + + TCFNodeStackFrame(TCFNode parent, String id, int frame_no) { + super(parent, id); + this.frame_no = frame_no; + children_regs = new TCFChildrenRegisters(this); + } + + int getFrameNo() { + return frame_no; + } + + @Override + void dispose() { + children_regs.dispose(); + super.dispose(); + } + + @Override + void dispose(String id) { + children_regs.dispose(id); + } + + @Override + public IRunControl.RunControlContext getRunContext() { + return parent.getRunContext(); + } + + @Override + public IMemory.MemoryContext getMemoryContext() { + return parent.getMemoryContext(); + } + + @Override + public boolean isRunning() { + return parent.isRunning(); + } + + @Override + public boolean isSuspended() { + return parent.isSuspended(); + } + + @Override + public String getAddress() { + assert Protocol.isDispatchThread(); + if (frame_no == 0) return parent.getAddress(); + if (stack_trace_context != null) { + return stack_trace_context.getReturnAddress().toString(); + } + return null; + } + + @Override + protected void getData(IChildrenCountUpdate result) { + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { + result.setChildCount(children_regs.size()); + } + else { + result.setChildCount(0); + } + } + + @Override + protected void getData(IChildrenUpdate result) { + int offset = 0; + TCFNode[] arr = null; + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { + arr = children_regs.toArray(); + } + else { + arr = null; + } + if (arr != null) { + Arrays.sort(arr); + for (TCFNode n : arr) { + if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) { + result.setChild(n, offset); + } + offset++; + } + } + } + + @Override + protected void getData(IHasChildrenUpdate result) { + if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) { + result.setHasChilren(children_regs.size() > 0); + } + else { + result.setHasChilren(false); + } + } + + @Override + protected void getData(ILabelUpdate result) { + result.setImageDescriptor(getImageDescriptor(getImageName()), 0); + String label = id; + Number n = null; + if (frame_no == 0 && parent.getAddress() != null) { + n = new BigInteger(parent.getAddress()); + } + else if (stack_trace_context != null) { + n = stack_trace_context.getReturnAddress(); + } + if (n == null) { + label = "..."; + } + else { + label = makeHexAddrString(n); + if (code_area != null && code_area.file != null) { + label += ": " + code_area.file + ", line " + (code_area.start_line + 1); + } + } + result.setLabel(label, 0); + } + + private String makeHexAddrString(Number n) { + BigInteger i = null; + if (n instanceof BigInteger) i = (BigInteger)n; + else i = new BigInteger(n.toString()); + String s = i.toString(16); + IMemory.MemoryContext m = getMemoryContext(); + int sz = (m != null ? m.getAddressSize() : 4) * 2; + int l = sz - s.length(); + if (l < 0) l = 0; + if (l > 16) l = 16; + return "0x0000000000000000".substring(0, 2 + l) + s; + } + + @Override + protected void invalidateNode(int flags) { + super.invalidateNode(flags); + if ((flags & CF_CHILDREN) != 0) { + children_regs.invalidate(); + } + } + + @Override + protected boolean validateContext(TCFRunnable done) { + assert data_command == null; + if (frame_no == 0) { + node_valid |= CF_CONTEXT; + return true; + } + IStackTrace st = model.getLaunch().getService(IStackTrace.class); + if (done != null) wait_list.add(done); + data_command = st.getContext(new String[]{ id }, new IStackTrace.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, IStackTrace.StackTraceContext[] context) { + if (data_command != token) return; + data_command = null; + if (error != null) { + node_error = error; + } + else { + stack_trace_context = context[0]; + } + BigInteger n = null; + ILineNumbers ln = model.getLaunch().getService(ILineNumbers.class); + if (node_error == null && ln != null) { + String s = getAddress(); + if (s != null) n = new BigInteger(s); + } + code_area = null; + if (n == null) { + node_valid |= CF_CONTEXT; + validateNode(null); + } + else { + BigInteger m = n.add(BigInteger.valueOf(1)); + data_command = ln.mapToSource(parent.id, n, m, new ILineNumbers.DoneMapToSource() { + public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) { + if (data_command != token) return; + data_command = null; + if (error != null) { + node_error = error; + } + else if (areas != null && areas.length > 0) { + for (ILineNumbers.CodeArea area : areas) { + if (code_area == null || area.start_line < code_area.start_line) { + code_area = area; + } + } + } + node_valid |= CF_CONTEXT; + validateNode(null); + } + }); + } + } + }); + return false; + } + + @Override + protected boolean validateChildren(TCFRunnable done) { + if (!children_regs.valid && !children_regs.validate(done)) return false; + node_valid |= CF_CHILDREN; + return true; + } + + @Override + protected String getImageName() { + if (isRunning()) return "icons/full/obj16/stckframe_running_obj.gif"; + return "icons/full/obj16/stckframe_obj.gif"; + } + + @Override + public int compareTo(TCFNode n) { + if (n instanceof TCFNodeStackFrame) { + TCFNodeStackFrame f = (TCFNodeStackFrame)n; + if (frame_no < f.frame_no) return -1; + if (frame_no > f.frame_no) return +1; + } + return id.compareTo(n.id); + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java new file mode 100644 index 000000000..f55cb8afb --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.model; + +import org.eclipse.debug.core.IRequest; +import org.eclipse.swt.widgets.Display; + +import com.windriver.tcf.api.protocol.Protocol; + +public abstract class TCFRunnable implements Runnable { + + private final IRequest monitor; + private final Display display; + + public TCFRunnable(Display display, IRequest monitor) { + this.monitor = monitor; + this.display = display; + Protocol.invokeLater(this); + } + + public void cancel() { + display.asyncExec(new Runnable() { + public void run() { + monitor.cancel(); + monitor.done(); + } + }); + } + + public void done() { + display.asyncExec(new Runnable() { + public void run() { + monitor.done(); + } + }); + } +} diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java new file mode 100644 index 000000000..824346801 --- /dev/null +++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java @@ -0,0 +1,305 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. 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 com.windriver.debug.tcf.ui.trace; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.part.ViewPart; + +import com.windriver.tcf.api.protocol.IChannel; +import com.windriver.tcf.api.protocol.IPeer; +import com.windriver.tcf.api.protocol.Protocol; +import com.windriver.tcf.api.core.AbstractChannel; + +public class TraceView extends ViewPart implements Protocol.ChannelOpenListener { + + private Composite parent; + private TabFolder tabs; + private Label no_data; + private final Map<TabItem,Page> tab2page = new HashMap<TabItem,Page>(); + + private class Page implements AbstractChannel.TraceListener { + + final AbstractChannel channel; + + private TabItem tab; + private Text text; + + private final StringBuffer bf = new StringBuffer(); + private int bf_line_cnt = 0; + private boolean closed; + + private final Thread update_thread = new Thread() { + public void run() { + synchronized (Page.this) { + while (!closed) { + if (bf_line_cnt > 0) { + Runnable r = new Runnable() { + public void run() { + String str = null; + int cnt = 0; + synchronized (Page.this) { + str = bf.toString(); + cnt = bf_line_cnt; + bf.setLength(0); + bf_line_cnt = 0; + } + if (text == null) return; + if (text.getLineCount() > 1000 - cnt) { + String s = text.getText(); + int n = 0; + int i = -1; + while (n < cnt) { + int j = s.indexOf('\n', i + 1); + if (j < 0) break; + i = j; + n++; + } + if (i >= 0) { + text.setText(s.substring(i + 1)); + } + } + text.append(str); + } + }; + getSite().getShell().getDisplay().asyncExec(r); + } + try { + Page.this.wait(1000); + } + catch (InterruptedException e) { + break; + } + } + } + } + }; + + Page(AbstractChannel channel) { + this.channel = channel; + update_thread.start(); + } + + public void dispose() { + synchronized (this) { + closed = true; + update_thread.interrupt(); + } + try { + update_thread.join(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + tab2page.remove(tab); + tab.dispose(); + tab = null; + text = null; + if (tab2page.isEmpty()) hideTabs(); + } + + public synchronized void onChannelClosed(Throwable error) { + if (error == null) { + channel.removeTraceListener(this); + getSite().getShell().getDisplay().asyncExec(new Runnable() { + public void run() { + dispose(); + } + }); + } + else { + bf.append("Channel terminated: " + error); + bf_line_cnt++; + } + } + + public synchronized void onMessageReceived(char type, String token, + String service, String name, byte[] data) { + try { + bf.append("Inp: "); + bf.append(type); + if (token != null) { + bf.append(' '); + bf.append(token); + } + if (service != null) { + bf.append(' '); + bf.append(service); + } + if (name != null) { + bf.append(' '); + bf.append(name); + } + if (data != null) { + int i = 0; + while (i < data.length) { + int j = i; + while (j < data.length && data[j] != 0) j++; + bf.append(' '); + bf.append(new String(data, i, j - i, "UTF8")); + if (j < data.length && data[j] == 0) j++; + i = j; + } + } + bf.append('\n'); + bf_line_cnt++; + } + catch (UnsupportedEncodingException x) { + x.printStackTrace(); + } + } + + public synchronized void onMessageSent(char type, String token, + String service, String name, byte[] data) { + try { + bf.append("Out: "); + bf.append(type); + if (token != null) { + bf.append(' '); + bf.append(token); + } + if (service != null) { + bf.append(' '); + bf.append(service); + } + if (name != null) { + bf.append(' '); + bf.append(name); + } + if (data != null) { + int i = 0; + while (i < data.length) { + int j = i; + while (j < data.length && data[j] != 0) j++; + bf.append(' '); + bf.append(new String(data, i, j - i, "UTF8")); + if (j < data.length && data[j] == 0) j++; + i = j; + } + } + bf.append('\n'); + bf_line_cnt++; + } + catch (UnsupportedEncodingException x) { + x.printStackTrace(); + } + } + } + + @Override + public void createPartControl(Composite parent) { + this.parent = parent; + Protocol.invokeAndWait(new Runnable() { + public void run() { + IChannel[] arr = Protocol.getOpenChannels(); + for (IChannel c : arr) onChannelOpen(c); + Protocol.addChannelOpenListener(TraceView.this); + } + }); + if (tab2page.size() == 0) hideTabs(); + } + + @Override + public void setFocus() { + if (tabs != null) tabs.setFocus(); + } + + @Override + public void dispose() { + final Page[] pages = tab2page.values().toArray(new Page[tab2page.size()]); + Protocol.invokeAndWait(new Runnable() { + public void run() { + Protocol.removeChannelOpenListener(TraceView.this); + for (Page p : pages) p.channel.removeTraceListener(p); + } + }); + for (Page p : pages) p.dispose(); + assert tab2page.isEmpty(); + if (tabs != null) { + tabs.dispose(); + tabs = null; + } + if (no_data != null) { + no_data.dispose(); + no_data = null; + } + super.dispose(); + } + + public void onChannelOpen(final IChannel channel) { + if (!(channel instanceof AbstractChannel)) return; + AbstractChannel c = (AbstractChannel)channel; + IPeer rp = c.getRemotePeer(); + final String name = rp.getName(); + final String host = rp.getAttributes().get(IPeer.ATTR_IP_HOST); + final String port = rp.getAttributes().get(IPeer.ATTR_IP_PORT); + final Page p = new Page(c); + c.addTraceListener(p); + getSite().getShell().getDisplay().asyncExec(new Runnable() { + public void run() { + showTabs(); + p.tab = new TabItem(tabs, SWT.NONE); + tab2page.put(p.tab, p); + String title = name; + if (host != null) { + title += ", " + host; + if (port != null) { + title += ":" + port; + } + } + p.tab.setText(title); + p.text = new Text(tabs, SWT.H_SCROLL | SWT.V_SCROLL | + SWT.BORDER | SWT.READ_ONLY | SWT.MULTI); + p.tab.setControl(p.text); + p.text.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE)); + } + }); + } + + private void showTabs() { + boolean b = false; + if (no_data != null) { + no_data.dispose(); + no_data = null; + b = true; + } + if (tabs == null) { + tabs = new TabFolder(parent, SWT.NONE); + b = true; + } + if (b) parent.layout(); + } + + private void hideTabs() { + boolean b = false; + if (tabs != null) { + tabs.dispose(); + tabs = null; + b = true; + } + if (!parent.isDisposed()) { + if (no_data == null) { + no_data = new Label(parent, SWT.NONE); + no_data.setText("No open communication channels at this time."); + b = true; + } + if (b) parent.layout(); + } + } +} |