diff options
21 files changed, 612 insertions, 93 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.tm.tcf.debug.ui/META-INF/MANIFEST.MF index 5b54cf108..026fddfa8 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.tm.tcf.debug.ui/META-INF/MANIFEST.MF @@ -12,6 +12,7 @@ Require-Bundle: org.eclipse.ui, org.eclipse.ui.console, org.eclipse.ui.workbench.texteditor, org.eclipse.text, + org.eclipse.jface.text, org.eclipse.debug.core, org.eclipse.debug.ui, org.eclipse.tm.tcf.debug, diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml b/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml index f027bda02..b3477b20d 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml +++ b/plugins/org.eclipse.tm.tcf.debug.ui/plugin.xml @@ -128,4 +128,20 @@ </specification> </extension> + <extension point="org.eclipse.debug.ui.detailPaneFactories"> + <detailFactories + class="org.eclipse.tm.internal.tcf.debug.ui.model.TCFDetailPaneFactory" + id="org.eclipse.tm.tcf.debug.DetailPaneFactory"> + <enablement> + <with variable="selection"> + <iterate> + <or> + <instanceof value="org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode"/> + </or> + </iterate> + </with> + </enablement> + </detailFactories> + </extension> + </plugin> diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/ResumeCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/ResumeCommand.java index 645ffc54e..6118ae199 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/ResumeCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/ResumeCommand.java @@ -46,10 +46,10 @@ public class ResumeCommand implements IResumeHandler { 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 = null; if (node instanceof TCFNodeExecContext) { - ctx = ((TCFNodeExecContext)node).getRunContext(); + if (!node.validateNode(this)) return; + ctx = ((TCFNodeExecContext)node).getRunContext().getData(); } if (ctx == null) { node = node.getParent(); @@ -82,10 +82,10 @@ public class ResumeCommand implements IResumeHandler { 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 = null; if (node instanceof TCFNodeExecContext) { - ctx = ((TCFNodeExecContext)node).getRunContext(); + if (!node.validateNode(this)) return; + ctx = ((TCFNodeExecContext)node).getRunContext().getData(); } if (ctx == null) { node = node.getParent(); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java index a9e8972f3..873c1a8e3 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/StepCommand.java @@ -49,12 +49,12 @@ abstract class StepCommand implements IDebugCommandHandler { 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 = null; if (node instanceof TCFNodeExecContext) { - ctx = ((TCFNodeExecContext)node).getRunContext(); + if (!node.validateNode(this)) return; + ctx = ((TCFNodeExecContext)node).getRunContext().getData(); } - if (!canExecute(ctx)) { + if (ctx == null || !canExecute(ctx)) { node = node.getParent(); } else { @@ -80,12 +80,12 @@ abstract class StepCommand implements IDebugCommandHandler { 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 = null; if (node instanceof TCFNodeExecContext) { - ctx = ((TCFNodeExecContext)node).getRunContext(); + if (!node.validateNode(this)) return; + ctx = ((TCFNodeExecContext)node).getRunContext().getData(); } - if (!canExecute(ctx)) { + if (ctx == null || !canExecute(ctx)) { node = node.getParent(); } else { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SuspendCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SuspendCommand.java index fa69c4454..55fcb80a7 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SuspendCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/SuspendCommand.java @@ -46,10 +46,10 @@ public class SuspendCommand implements ISuspendHandler { 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 = null; if (node instanceof TCFNodeExecContext) { - ctx = ((TCFNodeExecContext)node).getRunContext(); + if (!node.validateNode(this)) return; + ctx = ((TCFNodeExecContext)node).getRunContext().getData(); } if (ctx == null) { node = node.getParent(); @@ -82,17 +82,17 @@ public class SuspendCommand implements ISuspendHandler { 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 = null; if (node instanceof TCFNodeExecContext) { - ctx = ((TCFNodeExecContext)node).getRunContext(); + if (!node.validateNode(this)) return; + ctx = ((TCFNodeExecContext)node).getRunContext().getData(); } if (ctx == null) { node = node.getParent(); } else { set.add(ctx); - node = null; + break; } } } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/TerminateCommand.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/TerminateCommand.java index 2d2255743..a9aa268e0 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/TerminateCommand.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/commands/TerminateCommand.java @@ -45,10 +45,10 @@ public class TerminateCommand implements ITerminateHandler { TCFNode node = null; if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; while (node != null && !node.isDisposed()) { - if (!node.validateNode(this)) return; IRunControl.RunControlContext ctx = null; if (node instanceof TCFNodeExecContext) { - ctx = ((TCFNodeExecContext)node).getRunContext(); + if (!node.validateNode(this)) return; + ctx = ((TCFNodeExecContext)node).getRunContext().getData(); } if (ctx != null && ctx.canTerminate()) { res = true; @@ -73,10 +73,10 @@ public class TerminateCommand implements ITerminateHandler { TCFNode node = null; if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i]; while (node != null && !node.isDisposed()) { - if (!node.validateNode(this)) return; IRunControl.RunControlContext ctx = null; if (node instanceof TCFNodeExecContext) { - ctx = ((TCFNodeExecContext)node).getRunContext(); + if (!node.validateNode(this)) return; + ctx = ((TCFNodeExecContext)node).getRunContext().getData(); } if (ctx != null && ctx.canTerminate()) { set.add(ctx); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java index d3afa88f4..23dc827a9 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFAnnotationManager.java @@ -378,9 +378,10 @@ public class TCFAnnotationManager { public void run() { IRunControl.RunControlContext x = null; TCFNode n = (TCFNode)adaptable; - while (x == null && n != null) { + while (x == null && n != null && !n.isDisposed()) { if (n instanceof TCFNodeExecContext) { - x = ((TCFNodeExecContext)n).getRunContext(); + if (!n.validateNode(this)) return; + x = ((TCFNodeExecContext)n).getRunContext().getData(); } n = n.parent; } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java index 09c4f191e..c1fa139b2 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenExpressions.java @@ -1,3 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2008 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 org.eclipse.tm.internal.tcf.debug.ui.model; import java.util.HashMap; diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java index 4f7d7de54..8b69cc111 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenSubExpressions.java @@ -1,3 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2008 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 org.eclipse.tm.internal.tcf.debug.ui.model; import java.util.HashMap; diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFColumnPresentationExpression.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFColumnPresentationExpression.java index 88c102a66..4e60082df 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFColumnPresentationExpression.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFColumnPresentationExpression.java @@ -1,3 +1,13 @@ +/******************************************************************************* + * Copyright (c) 2008 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 org.eclipse.tm.internal.tcf.debug.ui.model; import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation; diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDetailPane.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDetailPane.java new file mode 100644 index 000000000..adb883112 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDetailPane.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2008 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 org.eclipse.tm.internal.tcf.debug.ui.model; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.eclipse.debug.ui.IDetailPane; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.tcf.protocol.Protocol; +import org.eclipse.ui.IWorkbenchPartSite; + +/** + * This detail pane uses a source viewer to display detailed information about the current + * selection. + */ +public class TCFDetailPane implements IDetailPane { + + public static final String ID = "org.eclipse.tm.tcf.debug.DetailPaneFactory"; + public static final String NAME = "TCF Detail Pane"; + public static final String DESC = "TCF Detail Pane"; + + private SourceViewer source_viewer; + private Display display; + private int generation; + @SuppressWarnings("unused") + private IWorkbenchPartSite part_site; + private final Document document = new Document(); + + public Control createControl(Composite parent) { + assert source_viewer == null; + source_viewer = new SourceViewer(parent, null, SWT.V_SCROLL | SWT.H_SCROLL); + source_viewer.setDocument(document); + source_viewer.setEditable(false); + Control control = source_viewer.getControl(); + GridData gd = new GridData(GridData.FILL_BOTH); + control.setLayoutData(gd); + display = control.getDisplay(); + return control; + } + + @SuppressWarnings("unchecked") + public void display(IStructuredSelection selection) { + if (source_viewer == null) return; + generation++; + final int g = generation; + final ArrayList<TCFNode> nodes = new ArrayList<TCFNode>(); + if (selection != null) { + Iterator iterator = selection.iterator(); + while (iterator.hasNext()) { + Object next = iterator.next(); + if (next instanceof TCFNode) nodes.add((TCFNode)next); + } + } + Protocol.invokeLater(new Runnable() { + public void run() { + if (g != generation) return; + final String s = getDetailText(nodes, this); + if (s == null) return; + display.asyncExec(new Runnable() { + public void run() { + if (g != generation) return; + document.set(s); + } + }); + } + }); + } + + private String getDetailText(ArrayList<TCFNode> nodes, Runnable done) { + if (!TCFNode.validateNodes(nodes, done)) return null; + StringBuffer bf = new StringBuffer(); + for (TCFNode n : nodes) { + if (n instanceof TCFNodeExpression) { + String s = ((TCFNodeExpression)n).getDetailText(done); + if (s == null) return null; + bf.append(s); + } + else { + bf.append(n.toString()); + bf.append('\n'); + } + } + return bf.toString(); + } + + public void dispose() { + if (source_viewer == null) return; + generation++; + if (source_viewer.getControl() != null) { + source_viewer.getControl().dispose(); + } + source_viewer = null; + } + + public String getDescription() { + return DESC; + } + + public String getID() { + return ID; + } + + public String getName() { + return NAME; + } + + public void init(IWorkbenchPartSite part_site) { + this.part_site = part_site; + } + + public boolean setFocus() { + if (source_viewer == null) return false; + source_viewer.getTextWidget().setFocus(); + return true; + } +} diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDetailPaneFactory.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDetailPaneFactory.java new file mode 100644 index 000000000..46d971560 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFDetailPaneFactory.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2008 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 org.eclipse.tm.internal.tcf.debug.ui.model; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.debug.ui.IDetailPane; +import org.eclipse.debug.ui.IDetailPaneFactory; +import org.eclipse.jface.viewers.IStructuredSelection; + +/** + * The TCF detail pane factory is contributed to the <code>org.eclipse.debug.ui.detailPaneFactories</code> + * extension. For any selection that contains TCFNode the factory can produce a <code>IDetailPane</code> object. + */ +public class TCFDetailPaneFactory implements IDetailPaneFactory { + + public IDetailPane createDetailPane(String paneID) { + assert paneID.equals(TCFDetailPane.ID); + return new TCFDetailPane(); + } + + public String getDefaultDetailPane(IStructuredSelection selection) { + return TCFDetailPane.ID; + } + + public String getDetailPaneDescription(String paneID) { + return TCFDetailPane.NAME; + } + + public String getDetailPaneName(String paneID) { + return TCFDetailPane.DESC; + } + + @SuppressWarnings("unchecked") + public Set getDetailPaneTypes(IStructuredSelection selection) { + HashSet<String> set = new HashSet<String>(); + set.add(TCFDetailPane.ID); + return set; + } +} diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java index 788cc8caf..1680e0f3e 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFMemoryBlockRetrieval.java @@ -171,7 +171,7 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { error("Context is disposed"); } else if (exec_ctx.validateNode(this)) { - IMemory.MemoryContext mem = exec_ctx.getMemoryContext(); + IMemory.MemoryContext mem = exec_ctx.getMemoryContext().getData(); if (mem == null) { error("Context does not provide memory access"); } @@ -249,7 +249,7 @@ class TCFMemoryBlockRetrieval implements IMemoryBlockRetrievalExtension { error("Context is disposed"); } else if (exec_ctx.validateNode(this)) { - final IMemory.MemoryContext mem = exec_ctx.getMemoryContext(); + final IMemory.MemoryContext mem = exec_ctx.getMemoryContext().getData(); if (mem == null) { error("Context does not provide memory access"); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java index 3fc77e0a7..e5d3b27d2 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFModel.java @@ -76,11 +76,13 @@ import org.eclipse.tm.internal.tcf.debug.ui.commands.StepReturnCommand; import org.eclipse.tm.internal.tcf.debug.ui.commands.SuspendCommand; import org.eclipse.tm.internal.tcf.debug.ui.commands.TerminateCommand; import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IToken; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.services.IMemory; import org.eclipse.tm.tcf.services.IProcesses; import org.eclipse.tm.tcf.services.IRegisters; import org.eclipse.tm.tcf.services.IRunControl; +import org.eclipse.tm.tcf.services.ISymbols; import org.eclipse.tm.tcf.util.TCFDataCache; import org.eclipse.tm.tcf.util.TCFTask; import org.eclipse.ui.IEditorInput; @@ -119,6 +121,12 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, private static final Map<ILaunchConfiguration,IEditorInput> editor_not_found = new HashMap<ILaunchConfiguration,IEditorInput>(); + private final Map<String,Map<String,TCFDataCache<ISymbols.Symbol>>> symbols = + new HashMap<String,Map<String,TCFDataCache<ISymbols.Symbol>>>(); + + private final Map<String,Map<String,TCFDataCache<String[]>>> symbol_children = + new HashMap<String,Map<String,TCFDataCache<String[]>>>(); + private TCFNodeLaunch launch_node; private boolean disposed; @@ -151,6 +159,10 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, if (node instanceof TCFNodeExecContext) { ((TCFNodeExecContext)node).onContextChanged(contexts[i]); } + Map<String,TCFDataCache<ISymbols.Symbol>> m = symbols.remove(contexts[i].getID()); + if (m != null) { + for (TCFDataCache<ISymbols.Symbol> s : m.values()) s.cancel(); + } } fireModelChanged(); } @@ -568,6 +580,52 @@ public class TCFModel implements IElementContentProvider, IElementLabelProvider, assert Protocol.isDispatchThread(); return id2node.get(id); } + + public TCFDataCache<ISymbols.Symbol> getSymbolInfoCache(String mem_id, final String sym_id) { + Map<String,TCFDataCache<ISymbols.Symbol>> m = symbols.get(mem_id); + if (m == null) symbols.put(mem_id, m = new HashMap<String,TCFDataCache<ISymbols.Symbol>>()); + TCFDataCache<ISymbols.Symbol> s = m.get(sym_id); + if (s == null) m.put(sym_id, s = new TCFDataCache<ISymbols.Symbol>(launch.getChannel()) { + @Override + protected boolean startDataRetrieval() { + ISymbols syms = getLaunch().getService(ISymbols.class); + if (sym_id == null || syms == null) { + set(null, null, null); + return true; + } + command = syms.getContext(sym_id, new ISymbols.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, ISymbols.Symbol sym) { + set(token, error, sym); + } + }); + return false; + } + }); + return s; + } + + public TCFDataCache<String[]> getSymbolChildrenCache(String mem_id, final String sym_id) { + Map<String,TCFDataCache<String[]>> m = symbol_children.get(mem_id); + if (m == null) symbol_children.put(mem_id, m = new HashMap<String,TCFDataCache<String[]>>()); + TCFDataCache<String[]> s = m.get(sym_id); + if (s == null) m.put(sym_id, s = new TCFDataCache<String[]>(launch.getChannel()) { + @Override + protected boolean startDataRetrieval() { + ISymbols syms = getLaunch().getService(ISymbols.class); + if (sym_id == null || syms == null) { + set(null, null, null); + return true; + } + command = syms.getChildren(sym_id, new ISymbols.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] ids) { + set(token, error, ids); + } + }); + return false; + } + }); + return s; + } public void update(IChildrenCountUpdate[] updates) { for (int i = 0; i < updates.length; i++) { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java index cc81311c5..f97cb55ee 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java @@ -154,7 +154,7 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo /** * Return address of this node. * For executable contexts and stack frames address is current PC. - * @return + * @return BigInteger - remote memory address that is associated with this node */ public BigInteger getAddress() { return null; @@ -332,7 +332,7 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo public abstract boolean validateNode(Runnable done); /** - * Subclasses can use this method to validate a collection of nodes. + * Clients can use this method to validate a collection of nodes. * Validation of multiple nodes is expensive and should be avoided * when possible. * @@ -342,7 +342,7 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo * @param nodes * @return true if all nodes are already valid, false if validation is started. */ - protected boolean validateNodes(Collection<TCFNode> nodes, Runnable done) { + public static boolean validateNodes(Collection<TCFNode> nodes, Runnable done) { TCFNode pending = null; for (TCFNode n : nodes) { if (!n.validateNode(null)) pending = n; diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java index efc8f95be..1266fa0ba 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java @@ -153,16 +153,12 @@ public class TCFNodeExecContext extends TCFNode { return line_info_cache; } - public IRunControl.RunControlContext getRunContext() { - assert Protocol.isDispatchThread(); - if (!run_context.isValid()) return null; - return run_context.getData(); + public TCFDataCache<IRunControl.RunControlContext> getRunContext() { + return run_context; } - public IMemory.MemoryContext getMemoryContext() { - assert Protocol.isDispatchThread(); - if (!mem_context.isValid()) return null; - return mem_context.getData(); + public TCFDataCache<IMemory.MemoryContext> getMemoryContext() { + return mem_context; } public boolean isRunning() { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java index 89308f55f..23a469442 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java @@ -1,5 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2008 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 org.eclipse.tm.internal.tcf.debug.ui.model; +import java.io.UnsupportedEncodingException; import java.math.BigInteger; import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; @@ -14,10 +25,12 @@ import org.eclipse.tm.internal.tcf.debug.ui.Activator; import org.eclipse.tm.internal.tcf.debug.ui.ImageCache; import org.eclipse.tm.tcf.protocol.IChannel; import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.services.IExpressions; import org.eclipse.tm.tcf.services.ISymbols; import org.eclipse.tm.tcf.util.TCFDataCache; +// TODO: elements of long arrays need to be shown in groups public class TCFNodeExpression extends TCFNode { private final String script; @@ -192,19 +205,24 @@ public class TCFNodeExpression extends TCFNode { value.wait(this); return false; } - String id = null; - if (value.getData() != null) id = value.getData().getTypeID(); - ISymbols syms = model.getLaunch().getService(ISymbols.class); - if (id == null || syms == null) { + IExpressions.Value v = value.getData(); + if (v == null) { set(null, null, null); return true; } - command = syms.getContext(id, new ISymbols.DoneGetContext() { - public void doneGetContext(IToken token, Exception error, ISymbols.Symbol sym) { - set(token, error, sym); - } - }); - return false; + String ctx_id = v.getExeContextID(); + String type_id = v.getTypeID(); + if (ctx_id == null || type_id == null) { + set(null, null, null); + return true; + } + TCFDataCache<ISymbols.Symbol> s = model.getSymbolInfoCache(ctx_id, type_id); + if (!s.validate()) { + s.wait(this); + return false; + } + set(null, s.getError(), s.getData()); + return true; } }; children = new TCFChildrenSubExpressions(this); @@ -267,71 +285,82 @@ public class TCFNodeExpression extends TCFNode { return type; } - private BigInteger toBigInteger(byte[] data, boolean big_endian, boolean sign_extension) { + private BigInteger toBigInteger(byte[] data, int offs, int size, boolean big_endian, boolean sign_extension) { byte[] temp = null; if (sign_extension) { - temp = new byte[data.length]; + temp = new byte[size]; } else { - temp = new byte[data.length + 1]; + temp = new byte[size + 1]; temp[0] = 0; // Extra byte to avoid sign extension by BigInteger } if (big_endian) { - System.arraycopy(data, 0, temp, sign_extension ? 0 : 1, data.length); + System.arraycopy(data, offs, temp, sign_extension ? 0 : 1, size); } else { - for (int i = 0; i < data.length; i++) { - temp[temp.length - i - 1] = data[i]; + for (int i = 0; i < size; i++) { + temp[temp.length - i - 1] = data[i + offs]; } } return new BigInteger(temp); } - private void setLabel(ILabelUpdate result, String name, int col, int radix) { + private String toNumberString(int radix, ISymbols.Symbol t, byte[] data, int offs, int size, boolean big_endian) { String s = null; - IExpressions.Value val = value.getData(); - if (val != null) { - byte[] data = val.getValue(); - if (data == null) s = "n/a"; - if (s == null && data.length == 0) s = ""; - if (s == null && radix == 10 && data.length <= 16) { - ISymbols.Symbol t = type.getData(); - if (t != null) { - switch (t.getTypeClass()) { - case integer: - s = toBigInteger(data, val.isBigEndian(), true).toString(); + if (data == null) s = "N/A"; + if (s == null && size == 0) s = ""; + if (s == null && radix == 10 && size <= 16) { + if (t != null) { + switch (t.getTypeClass()) { + case integer: + s = toBigInteger(data, offs, size, big_endian, true).toString(); + break; + case real: + switch (t.getSize()) { + case 4: + s = Float.toString(Float.intBitsToFloat(toBigInteger( + data, offs, size, big_endian, true).intValue())); break; - case real: - switch (t.getSize()) { - case 4: - s = Float.toString(Float.intBitsToFloat(toBigInteger( - data, val.isBigEndian(), true).intValue())); - break; - case 8: - s = Double.toString(Double.longBitsToDouble(toBigInteger( - data, val.isBigEndian(), true).longValue())); - break; - } + case 8: + s = Double.toString(Double.longBitsToDouble(toBigInteger( + data, offs, size, big_endian, true).longValue())); break; } - } - } - if (s == null && data.length <= 16) { - s = toBigInteger(data, val.isBigEndian(), false).toString(radix); - switch (radix) { - case 8: - if (!s.startsWith("0")) s = "0" + s; - break; - case 16: - int l = data.length * 2 - s.length(); - if (l < 0) l = 0; - if (l > 16) l = 16; - s = "0000000000000000".substring(0, l) + s; break; } } } + if (s == null && size <= 16) { + s = toBigInteger(data, offs, size, big_endian, false).toString(radix); + switch (radix) { + case 8: + if (!s.startsWith("0")) s = "0" + s; + break; + case 16: + int l = size * 2 - s.length(); + if (l < 0) l = 0; + if (l > 16) l = 16; + s = "0000000000000000".substring(0, l) + s; + break; + } + } + if (s == null) s = "N/A"; + return s; + } + + private String toNumberString(int radix) { + String s = null; + IExpressions.Value val = value.getData(); + if (val != null) { + byte[] data = val.getValue(); + s = toNumberString(radix, type.getData(), data, 0, data.length, val.isBigEndian()); + } if (s == null) s = "..."; + return s; + } + + private void setLabel(ILabelUpdate result, String name, int col, int radix) { + String s = toNumberString(radix); if (name == null) { result.setLabel(s, col); } @@ -371,7 +400,7 @@ public class TCFNodeExpression extends TCFNode { } } } - if (s == null) s = ""; + if (s == null) s = "N/A"; result.setLabel(s, col); } @@ -386,12 +415,21 @@ public class TCFNodeExpression extends TCFNode { Throwable error = expression.getError(); if (error == null) error = value.getError(); if (error == null) error = type.getError(); + String[] cols = result.getColumnIds(); if (error != null) { - result.setForeground(new RGB(255, 0, 0), 0); - result.setLabel(name + ": " + error.getMessage(), 0); + if (cols == null || cols.length <= 1) { + result.setForeground(new RGB(255, 0, 0), 0); + result.setLabel(name + ": N/A", 0); + } + else { + result.setLabel(name, 0); + for (int i = 1; i < cols.length; i++) { + result.setForeground(new RGB(255, 0, 0), i); + result.setLabel("N/A", i); + } + } } else { - String[] cols = result.getColumnIds(); if (cols == null) { setLabel(result, name, 0, 16); } @@ -414,6 +452,174 @@ public class TCFNodeExpression extends TCFNode { } } } + + private void appendErrorText(StringBuffer bf, Throwable error) { + if (error == null) return; + bf.append("Exception: "); + for (;;) { + String s = error.getLocalizedMessage(); + if (s == null || s.length() == 0) s = error.getClass().getName(); + bf.append(s); + if (!s.endsWith("\n")) bf.append('\n'); + Throwable cause = error.getCause(); + if (cause == null) return; + bf.append("Caused by: "); + error = cause; + } + } + + private boolean appendArrayValueText(StringBuffer bf, int level, ISymbols.Symbol t, + byte[] data, int offs, int size, boolean big_endian, Runnable done) { + TCFDataCache<ISymbols.Symbol> c = model.getSymbolInfoCache(t.getExeContextID(), t.getBaseTypeID()); + if (!c.validate()) { + c.wait(done); + return false; + } + ISymbols.Symbol b = c.getData(); + int length = t.getLength(); + if (level == 0) { + if (size == length) { + try { + bf.append('"'); + String s = new String(data, offs, size, "ASCII"); + int l = s.length(); + String end_q = "\""; + if (l > 300) { + l = 300; + end_q = "..."; + } + for (int i = 0; i < l; i++) { + char ch = s.charAt(i); + if (ch < ' ') ch = ' '; + bf.append(ch); + } + bf.append(end_q); + } + catch (UnsupportedEncodingException e) { + Protocol.log("ASCII", e); + } + bf.append('\n'); + } + } + if (b == null) return true; + int elem_size = size / length; + bf.append('['); + for (int n = 0; n < length; n++) { + if (n >= 100) { + bf.append("..."); + break; + } + if (n > 0) bf.append(", "); + if (!appendValueText(bf, level + 1, b, data, offs + n * elem_size, elem_size, big_endian, done)) return false; + } + bf.append(']'); + if (level == 0) bf.append('\n'); + return true; + } + + private boolean appendCompositeValueText(StringBuffer bf, int level, ISymbols.Symbol t, + byte[] data, int offs, int size, boolean big_endian, Runnable done) { + TCFDataCache<String[]> c = model.getSymbolChildrenCache(t.getExeContextID(), t.getID()); + if (!c.validate()) { + c.wait(done); + return false; + } + String[] ids = c.getData(); + if (ids == null) return true; + bf.append('{'); + for (String id : ids) { + if (id != ids[0]) bf.append(", "); + TCFDataCache<ISymbols.Symbol> s = model.getSymbolInfoCache(t.getExeContextID(), id); + if (!s.validate()) { + s.wait(done); + return false; + } + ISymbols.Symbol f = s.getData(); + if (!appendValueText(bf, level + 1, f, data, offs + f.getOffset(), f.getSize(), big_endian, done)) return false; + } + bf.append('}'); + return true; + } + + private boolean appendValueText(StringBuffer bf, int level, ISymbols.Symbol t, + byte[] data, int offs, int size, boolean big_endian, Runnable done) { + if (data == null) return true; + switch (t.getTypeClass()) { + case enumeration: + case integer: + case cardinal: + case real: + if (level == 0) { + bf.append("Dec: "); + bf.append(toNumberString(10, t, data, offs, size, big_endian)); + bf.append("\n"); + bf.append("Oct: "); + bf.append(toNumberString(8, t, data, offs, size, big_endian)); + bf.append("\n"); + bf.append("Hex: "); + bf.append(toNumberString(16, t, data, offs, size, big_endian)); + bf.append("\n"); + } + else if (t.getTypeClass() == ISymbols.TypeClass.cardinal) { + bf.append("0x"); + bf.append(toNumberString(16, t, data, offs, size, big_endian)); + } + else { + bf.append(toNumberString(10, t, data, offs, size, big_endian)); + } + break; + case pointer: + case function: + if (level == 0) { + bf.append("Oct: "); + bf.append(toNumberString(8, t, data, offs, size, big_endian)); + bf.append("\n"); + bf.append("Hex: "); + bf.append(toNumberString(16, t, data, offs, size, big_endian)); + bf.append("\n"); + } + else { + bf.append("0x"); + bf.append(toNumberString(16, t, data, offs, size, big_endian)); + } + break; + case array: + if (!appendArrayValueText(bf, level, t, data, offs, size, big_endian, done)) return false; + break; + case composite: + if (!appendCompositeValueText(bf, level, t, data, offs, size, big_endian, done)) return false; + break; + default: + bf.append('?'); + break; + } + return true; + } + + String getDetailText(Runnable done) { + StringBuffer bf = new StringBuffer(); + appendErrorText(bf, expression.getError()); + appendErrorText(bf, value.getError()); + appendErrorText(bf, type.getError()); + if (bf.length() == 0) { + IExpressions.Value v = value.getData(); + if (v != null) { + byte[] data = v.getValue(); + boolean big_endian = v.isBigEndian(); + ISymbols.Symbol t = type.getData(); + if (t != null) { + if (!appendValueText(bf, 0, t, data, 0, data.length, big_endian, done)) return null; + } + else { + bf.append("Hex: "); + bf.append(toNumberString(16, t, data, 0, data.length, big_endian)); + bf.append("\n"); + bf.append("Value type is not available\n"); + } + } + } + return bf.toString(); + } @Override protected void getData(IChildrenCountUpdate result) { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java index ce272c8c2..1534bf51d 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java @@ -82,23 +82,41 @@ public class TCFNodeStackFrame extends TCFNode { set(null, null, null); return true; } + IMemory.MemoryContext mem_ctx = null; + TCFNode p = parent; + while (p != null) { + if (p instanceof TCFNodeExecContext) { + TCFDataCache<IMemory.MemoryContext> cache = ((TCFNodeExecContext)p).getMemoryContext(); + if (!cache.validate()) { + cache.wait(this); + return false; + } + mem_ctx = cache.getData(); + if (mem_ctx != null) break; + } + p = p.parent; + } TCFSourceRef l = line_info_cache.get(n); if (l != null) { + l.context = mem_ctx; set(null, null, l); return true; } ILineNumbers ln = model.getLaunch().getService(ILineNumbers.class); if (ln == null) { l = new TCFSourceRef(); + l.context = mem_ctx; l.address = n; set(null, null, l); return true; } final BigInteger n0 = n; final BigInteger n1 = n0.add(BigInteger.valueOf(1)); + final IMemory.MemoryContext ctx = mem_ctx; command = ln.mapToSource(parent.id, n0, n1, new ILineNumbers.DoneMapToSource() { public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) { TCFSourceRef l = new TCFSourceRef(); + l.context = ctx; l.address = n0; if (error == null && areas != null && areas.length > 0) { for (ILineNumbers.CodeArea area : areas) { @@ -289,7 +307,7 @@ public class TCFNodeStackFrame extends TCFNode { result.setLabel("...", 0); } else { - String label = makeHexAddrString(l.address); + String label = makeHexAddrString(l.context, l.address); if (l.area != null && l.area.file != null) { label += ": " + l.area.file + ", line " + l.area.start_line; } @@ -299,12 +317,11 @@ public class TCFNodeStackFrame extends TCFNode { } } - private String makeHexAddrString(Number n) { + private String makeHexAddrString(IMemory.MemoryContext m, 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 = ((TCFNodeExecContext)parent).getMemoryContext(); int sz = (m != null ? m.getAddressSize() : 4) * 2; int l = sz - s.length(); if (l < 0) l = 0; diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java index 00405ed49..049edcd7c 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFSourceRef.java @@ -13,11 +13,13 @@ package org.eclipse.tm.internal.tcf.debug.model; import java.math.BigInteger; import org.eclipse.tm.tcf.services.ILineNumbers; +import org.eclipse.tm.tcf.services.IMemory; /** * Objects of this class represent a mapping between an address and source code area. */ public class TCFSourceRef { + public IMemory.MemoryContext context; public BigInteger address; public ILineNumbers.CodeArea area; public Throwable error; diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java index 5d1a2f98c..7634707e9 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/ExpressionsProxy.java @@ -99,6 +99,10 @@ public class ExpressionsProxy implements IExpressions { return (String)props.get(VAL_TYPE); } + public String getExeContextID() { + return (String)props.get(VAL_EXE_ID); + } + public byte[] getValue() { return value; } diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IExpressions.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IExpressions.java index dfa5f1064..0c355e3d2 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IExpressions.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/services/IExpressions.java @@ -126,6 +126,12 @@ public interface IExpressions extends IService { String getTypeID(); /** + * Get execution context ID (thread or process) that owns type symbol for this value. + * @return execution context ID. + */ + String getExeContextID(); + + /** * Check endianess of the values. * Big endian means decreasing numeric significance with increasing byte number. * @return true if big endian. @@ -151,6 +157,7 @@ public interface IExpressions extends IService { static final String VAL_CLASS = "Class", VAL_TYPE = "Type", + VAL_EXE_ID = "ExeID", VAL_BIG_ENDIAN = "BigEndian"; /** |