Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties9
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml14
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/FetchMoreChildrenAction.java113
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java74
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java3
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java9
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties6
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/FetchMoreChildrenEvent.java34
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java105
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java426
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMProvider.java108
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Message.properties2
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Messages.java2
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGdbDebugPreferenceConstants.java17
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java27
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java15
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java24
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java22
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/IMIExpressions.java101
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java368
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java1377
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java2
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties3
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java24
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIMaintenance.java25
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildCount.java44
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildren.java44
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIEnablePrettyPrinting.java31
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoNumChildren.java16
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoPathExpression.java7
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarListChildren.java18
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarSetUpdateRange.java40
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/ExprMetaGetVarInfo.java79
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIDisplayHint.java135
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVar.java95
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarChange.java106
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarCreateInfo.java55
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarInfoNumChildrenInfo.java6
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarListChildrenInfo.java24
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarUpdateInfo.java41
40 files changed, 3373 insertions, 278 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties
index 642aa5b1d3f..4a343bfaf70 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties
@@ -8,6 +8,7 @@
# Contributors:
# Ericsson - initial API and implementation
# IBM Corporation
+# Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
###############################################################################
pluginName=GDB DSF Debugger Integration UI
providerName=Eclipse CDT
@@ -41,3 +42,11 @@ command.nextTraceRecord.name=Next Trace Record
command.prevTraceRecord.name=Previous Trace Record
command.nextTraceRecord.description=Select Next Trace Record
command.prevTraceRecord.description=Select Previous Trace Record
+
+category.description = C/C++ debugging with the DSF GDB debugger
+category.name = CDT DSF-GDB - GDB Debugging
+activity.description = C/C++ debugging with the DSF GDB debugger
+activity.name = CDT DSF-GDB - GDB Debugging
+
+# Pretty Printing
+action.fetchMoreChildren.label=Fetch More Children
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml
index b161b9d1d48..a71b10471e1 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml
@@ -459,5 +459,17 @@
</enablement>
</consolePageParticipant>
</extension>
-
+ <extension point="org.eclipse.ui.popupMenus">
+ <objectContribution
+ adaptable="false"
+ id="org.eclipse.cdt.dsf.gdb.ui.objectContribution.incompleteChildren"
+ objectClass="org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMNode$IncompleteChildrenVMC">
+ <action
+ class="org.eclipse.cdt.dsf.gdb.internal.ui.actions.FetchMoreChildrenAction"
+ id="org.eclipse.cdt.dsf.gdb.ui.action.fetchMoreChildren"
+ label="%action.fetchMoreChildren.label"
+ menubarPath="renderGroup">
+ </action>
+ </objectContribution>
+ </extension>
</plugin>
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/FetchMoreChildrenAction.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/FetchMoreChildrenAction.java
new file mode 100644
index 00000000000..84842f340c6
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/FetchMoreChildrenAction.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.internal.ui.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.AbstractVMProviderActionDelegate;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.FetchMoreChildrenEvent;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbExpressionVMProvider;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMNode;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMNode.IncompleteChildrenVMC;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * @since 3.0
+ */
+public class FetchMoreChildrenAction extends AbstractVMProviderActionDelegate
+ implements IObjectActionDelegate {
+
+ private ISelection selection;
+
+ public void run(IAction action) {
+ IncompleteChildrenVMC incompleteChildrenVmc = getIncompleteChildrenVMC();
+
+ if (incompleteChildrenVmc != null) {
+ if (selection instanceof ITreeSelection) {
+ ITreeSelection treeSelection = (ITreeSelection) selection;
+ TreePath path = treeSelection.getPaths()[0];
+
+ IVMNode node = incompleteChildrenVmc.getVMNode();
+
+ IExpressionDMContext exprCtx = incompleteChildrenVmc.getParentDMContext();
+ ((GdbVariableVMNode) node).incrementChildCountLimit(exprCtx);
+ final FetchMoreChildrenEvent fetchMoreChildrenEvent = new FetchMoreChildrenEvent(exprCtx, path);
+ final AbstractVMProvider vmProvider = (AbstractVMProvider) getVMProvider();
+ vmProvider.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ vmProvider.handleEvent(fetchMoreChildrenEvent);
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public void init(IViewPart view) {
+ super.init(view);
+ updateEnablement();
+ }
+
+ @Override
+ public void debugContextChanged(DebugContextEvent event) {
+ super.debugContextChanged(event);
+ updateEnablement();
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ this.selection = selection;
+ updateEnablement();
+ }
+
+ private void updateEnablement() {
+ boolean enabled = false;
+ if ((getVMProvider() instanceof GdbExpressionVMProvider)
+ || (getVMProvider() instanceof GdbVariableVMProvider)) {
+ enabled = (getIncompleteChildrenVMC() != null);
+ }
+ getAction().setEnabled(enabled);
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ if (targetPart instanceof IViewPart) {
+ init((IViewPart) targetPart);
+ }
+ }
+
+ private IncompleteChildrenVMC getIncompleteChildrenVMC() {
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection ss = (IStructuredSelection) selection;
+
+ if (ss.size() == 1) {
+ // Only single selection is supported.
+ Object selectedObject = ss.getFirstElement();
+ if (selectedObject instanceof IncompleteChildrenVMC) {
+ return (IncompleteChildrenVMC) selectedObject;
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java
index 792640f2593..97090690e8c 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbDebugPreferencePage.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.preferences;
@@ -15,9 +16,13 @@ import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.IntegerFieldEditor;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
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.ui.IWorkbench;
@@ -29,6 +34,26 @@ import org.eclipse.ui.PlatformUI;
*/
public class GdbDebugPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+ /**
+ * A vehicle in order to be able to register a selection listener with
+ * a {@link BooleanFieldEditor}.
+ */
+ private class ListenableBooleanFieldEditor extends BooleanFieldEditor {
+
+ public ListenableBooleanFieldEditor(
+ String name,
+ String labelText,
+ int style,
+ Composite parent) {
+ super(name, labelText, style, parent);
+ }
+
+ @Override
+ public Button getChangeControl(Composite parent) {
+ return super.getChangeControl(parent);
+ }
+ }
+
public GdbDebugPreferencePage() {
super(FLAT);
IPreferenceStore store= GdbUIPlugin.getDefault().getPreferenceStore();
@@ -100,6 +125,55 @@ public class GdbDebugPreferencePage extends FieldEditorPreferencePage implements
// need to set layout again
group.setLayout(groupLayout);
+ group = new Group(parent, SWT.NONE);
+ group.setText(MessagesForPreferences.GdbDebugPreferencePage_prettyPrinting_label);
+ groupLayout = new GridLayout(3, false);
+ group.setLayout(groupLayout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ final ListenableBooleanFieldEditor enablePrettyPrintingField = new ListenableBooleanFieldEditor(
+ IGdbDebugPreferenceConstants.PREF_ENABLE_PRETTY_PRINTING,
+ MessagesForPreferences.GdbDebugPreferencePage_enablePrettyPrinting_label1 + "\n" //$NON-NLS-1$
+ + MessagesForPreferences.GdbDebugPreferencePage_enablePrettyPrinting_label2,
+ SWT.NONE, group);
+
+ enablePrettyPrintingField.fillIntoGrid(group, 3);
+ addField(enablePrettyPrintingField);
+
+ final Composite indentHelper = new Composite(group, SWT.NONE);
+ GridLayout helperLayout = new GridLayout(3, false);
+ indentHelper.setLayout(helperLayout);
+ GridData helperData = new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1);
+ helperData.horizontalIndent = 20;
+ indentHelper.setLayoutData(helperData);
+
+ final IntegerFieldEditor childCountLimitField = new IntegerFieldEditor(
+ IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ MessagesForPreferences.GdbDebugPreferencePage_initialChildCountLimitForCollections_label,
+ indentHelper);
+
+ childCountLimitField.setValidRange(1, 10000);
+ childCountLimitField.fillIntoGrid(indentHelper, 3);
+
+ IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore();
+ boolean prettyPrintingEnabled = store
+ .getBoolean(IGdbDebugPreferenceConstants.PREF_ENABLE_PRETTY_PRINTING);
+ childCountLimitField.setEnabled(prettyPrintingEnabled, indentHelper);
+
+ addField(childCountLimitField);
+
+ enablePrettyPrintingField.getChangeControl(group).addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ boolean enabled = enablePrettyPrintingField.getBooleanValue();
+ childCountLimitField.setEnabled(enabled, indentHelper);
+ }
+ });
+
+ // need to set layouts again
+ indentHelper.setLayout(helperLayout);
+ group.setLayout(groupLayout);
}
@Override
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java
index ed11c079108..2efb43368b9 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/GdbPreferenceInitializer.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.preferences;
@@ -25,5 +26,7 @@ public class GdbPreferenceInitializer extends AbstractPreferenceInitializer {
store.setDefault(IGdbDebugPreferenceConstants.PREF_TRACES_ENABLE, true);
store.setDefault(IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB, true);
store.setDefault(IGdbDebugPreferenceConstants.PREF_USE_INSPECTOR_HOVER, true);
+ store.setDefault(IGdbDebugPreferenceConstants.PREF_ENABLE_PRETTY_PRINTING, true);
+ store.setDefault(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS, 100);
}
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java
index 74af3e2e94d..1687ac00a6a 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.preferences;
@@ -23,6 +24,14 @@ class MessagesForPreferences extends NLS {
public static String GdbDebugPreferencePage_autoTerminateGdb_label;
public static String GdbDebugPreferencePage_hover_label;
public static String GdbDebugPreferencePage_useInspectorHover_label;
+ /** @since 3.0 */
+ public static String GdbDebugPreferencePage_prettyPrinting_label;
+ /** @since 3.0 */
+ public static String GdbDebugPreferencePage_enablePrettyPrinting_label1;
+ /** @since 3.0 */
+ public static String GdbDebugPreferencePage_enablePrettyPrinting_label2;
+ /** @since 3.0 */
+ public static String GdbDebugPreferencePage_initialChildCountLimitForCollections_label;
static {
// initialize resource bundle
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties
index 5718c184ad5..b5995a08afa 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/preferences/MessagesForPreferences.properties
@@ -7,6 +7,7 @@
#
# Contributors:
# Ericsson - initial API and implementation
+# Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
###############################################################################
GdbDebugPreferencePage_description=General settings for GDB Debugging
@@ -19,3 +20,8 @@ GdbDebugPreferencePage_autoTerminateGdb_label=Terminate GDB when last process ex
GdbDebugPreferencePage_hover_label=Debug Text Hover
GdbDebugPreferencePage_useInspectorHover_label=Use enhanced debug hover
+
+GdbDebugPreferencePage_prettyPrinting_label=Pretty Printing
+GdbDebugPreferencePage_enablePrettyPrinting_label1=Enable pretty printers in variable/expression tree
+GdbDebugPreferencePage_enablePrettyPrinting_label2=(requires python-enabled GDB)
+GdbDebugPreferencePage_initialChildCountLimitForCollections_label=For collections, initially limit child count to
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/FetchMoreChildrenEvent.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/FetchMoreChildrenEvent.java
new file mode 100644
index 00000000000..ac7617eeb21
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/FetchMoreChildrenEvent.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Event to fetch additional children for and expression context.
+ *
+ * @since 3.0
+ */
+public class FetchMoreChildrenEvent extends AbstractDMEvent<IExpressionDMContext> {
+
+ private TreePath path;
+
+ public FetchMoreChildrenEvent(IExpressionDMContext exprCtx, TreePath path) {
+ super(exprCtx);
+ this.path = path;
+ }
+
+ public TreePath getPath() {
+ return path;
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java
index dbd2caf21ee..424438918f6 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java
@@ -8,10 +8,14 @@
* Contributors:
* Freescale Semiconductor - initial API and implementation
* Axel Mueller - Bug 306555 - Add support for cast to type / view as array (IExpressions2)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.DsfCastToTypeSupport;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.DisabledExpressionVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionManagerVMNode;
@@ -24,12 +28,23 @@ import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.SyncRegisterDataAccess;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMNode;
+import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
+import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMNode.IncompleteChildrenVMC;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.TreePath;
/**
* A specialization of ExpressionVMProvider that uses a GDB-specific variable VM
@@ -38,12 +53,35 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont
@SuppressWarnings("restriction")
public class GdbExpressionVMProvider extends ExpressionVMProvider {
+ private IPropertyChangeListener fPreferencesListener;
+
/**
* Constructor (passthru)
*/
public GdbExpressionVMProvider(AbstractVMAdapter adapter,
IPresentationContext context, DsfSession session) {
super(adapter, context, session);
+ final IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore();
+
+ Integer childCountLimit = store.getInt(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS);
+ if (childCountLimit != 0) {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ childCountLimit);
+ }
+
+ fPreferencesListener = new IPropertyChangeListener() {
+ public void propertyChange(final PropertyChangeEvent event) {
+ handlePropertyChanged(store, event);
+ }};
+ store.addPropertyChangeListener(fPreferencesListener);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ final IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore();
+ store.removePropertyChangeListener(fPreferencesListener);
}
/**
@@ -126,4 +164,71 @@ public class GdbExpressionVMProvider extends ExpressionVMProvider {
*/
setRootNode(rootNode);
}
+
+ @Override
+ public void handleEvent(Object event, final RequestMonitor rm) {
+ if (event instanceof DoubleClickEvent && !isDisposed()) {
+
+ final ISelection selection= ((DoubleClickEvent) event).getSelection();
+ if (selection instanceof IStructuredSelection) {
+
+ Object element= ((IStructuredSelection) selection).getFirstElement();
+ if (element instanceof IncompleteChildrenVMC) {
+
+ IncompleteChildrenVMC incompleteChildrenVmc = ((IncompleteChildrenVMC) element);
+ IVMNode node = incompleteChildrenVmc.getVMNode();
+ if (node instanceof GdbVariableVMNode && node.getVMProvider() == this) {
+
+ if (selection instanceof ITreeSelection) {
+ ITreeSelection treeSelection = (ITreeSelection) selection;
+ TreePath path = treeSelection.getPaths()[0];
+
+ IExpressionDMContext exprCtx = incompleteChildrenVmc.getParentDMContext();
+ ((GdbVariableVMNode) node).incrementChildCountLimit(exprCtx);
+
+ // replace double click event with the fetch more children event.
+ final FetchMoreChildrenEvent fetchMoreChildrenEvent = new FetchMoreChildrenEvent(
+ exprCtx, path);
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ handleEvent(fetchMoreChildrenEvent, rm);
+ }
+ });
+
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ super.handleEvent(event, rm);
+ }
+
+ /**
+ * @param store
+ * @param event
+ *
+ * @since 3.0
+ */
+ protected void handlePropertyChanged(final IPreferenceStore store, final PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property)) {
+ Integer childCountLimit = store.getInt(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS);
+
+ if (childCountLimit != 0) {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ childCountLimit);
+ } else {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ null);
+ }
+
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ handleEvent(event);
+ }
+ });
+ }
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java
index 45c9fa73075..934a304ac01 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java
@@ -7,23 +7,48 @@
*
* Contributors:
* Freescale Semiconductor - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.eclipse.cdt.debug.internal.core.ICWatchpointTarget;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMNode;
+import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
+import org.eclipse.cdt.dsf.mi.service.IMIExpressions;
import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IExpression;
+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.IModelDelta;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.TreePath;
/**
* Specialization of DSF's VariableVMNode. See
@@ -31,6 +56,42 @@ import org.eclipse.core.runtime.Status;
*/
public class GdbVariableVMNode extends VariableVMNode {
+ // Notes on gdb's pretty printer support (bug 302121):
+ // If
+ // - an expression has children
+ // - and those children are provided by a pretty printer
+ // - and the expression is not yet initialized
+ // the expression might have a large number of children. Asking gdb to
+ // provide all children, or even just the number of all children, will
+ // lead to extremely slow response times.
+ // Furthermore, there are C/C++ data structures (e.g. linked lists) that
+ // can lead to endless loops if not correctly initialized and a pretty
+ // printer tries to obtain the number of children. In this case, gdb
+ // will never return.
+ //
+ // In order to address this problem, IMIExpressions deriving from
+ // IExpressions has been introduced.
+ // It lets the client specify a maximum number of children to be considered,
+ // both when asking the number of sub-expression, or the sub-expressions
+ // itself.
+ //
+ // The algorithm how it is used is as following:
+ // - We don't show all children in the UI, but only up to a certain limit.
+ // A special context type IncompleteChildrenVMC is used to show that
+ // there are more children than those currently visible.
+ // The user can fetch more children on demand.
+ // - updateHasElementsInSessionThread asks only for up to one child.
+ // - updateElementCountInSessionThread checks whether the expression
+ // requires a limit on the child count limit. If yes, it asks
+ // the expression service for up to limit + 1 children. The + 1
+ // represent the child for the <...more children...> node. I.e.,
+ // if the returned number of children is limit + 1, then there is
+ // an <...more_children...> node. Otherwise, there is not.
+ // - updateElementsInSessionThread sooner or later delegates to
+ // fillUpdateWithVMCs. fillUpdateWithVMCs checks whether there are
+ // limit + 1 children, and if so, will create an IncompleteChildrenVMC
+ // for the last child, discarding the original expression context.
+
/**
* Specialization of VariableVMNode.VariableExpressionVMC that participates
* in the "Add Watchpoint" object contribution action.
@@ -98,8 +159,7 @@ public class GdbVariableVMNode extends VariableVMNode {
@Override
public void handleCompleted() {
if (isSuccess()) {
- assert getData().getSize() > 0;
- request.setCanCreate(true);
+ request.setCanCreate(getData().getSize() > 0);
}
request.setStatus(getStatus());
request.done();
@@ -123,6 +183,41 @@ public class GdbVariableVMNode extends VariableVMNode {
};
/**
+ * The special context representing more children to be available.
+ *
+ * @since 3.0
+ */
+ public class IncompleteChildrenVMC extends AbstractVMContext {
+
+ private IExpressionDMContext parentDmc;
+
+ public IncompleteChildrenVMC(IExpressionDMContext exprDmc, int childCountLimit) {
+ super(GdbVariableVMNode.this);
+ this.parentDmc = exprDmc;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof IncompleteChildrenVMC &&
+ ((IncompleteChildrenVMC)obj).parentDmc.equals(parentDmc);
+ }
+
+ @Override
+ public int hashCode() {
+ return parentDmc.hashCode();
+ }
+
+ public IExpressionDMContext getParentDMContext() {
+ return parentDmc;
+ }
+ }
+
+ /**
+ * Maps expressions to their current limit on the maximum number of children.
+ */
+ private Map<IExpressionDMContext, Integer> childCountLimits = new HashMap<IExpressionDMContext, Integer>();
+
+ /**
* Utility method to create an IStatus object for an internal error
*/
private static Status internalError() {
@@ -149,4 +244,331 @@ public class GdbVariableVMNode extends VariableVMNode {
protected IDMVMContext createVMContext(IDMContext dmc) {
return new GdbVariableExpressionVMC(dmc);
}
+
+ @Override
+ protected void updateHasElementsInSessionThread(final IHasChildrenUpdate update) {
+ if (update.getElement() instanceof IncompleteChildrenVMC) {
+ update.setHasChilren(false);
+ update.done();
+ return;
+ }
+
+ super.updateHasElementsInSessionThread(update);
+ }
+
+ @Override
+ protected void updateElementCountInSessionThread(final IChildrenCountUpdate update) {
+ // Get the data model context object for the current node in the hierarchy.
+
+ final IExpressionDMContext expressionDMC = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressionDMContext.class);
+
+ if ( expressionDMC != null ) {
+ final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
+
+ if (expressionService == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ if (expressionService instanceof IMIExpressions) {
+ final IMIExpressions miExpressions = (IMIExpressions) expressionService;
+
+ miExpressions.safeToAskForAllSubExpressions(expressionDMC,
+ new ViewerDataRequestMonitor<Boolean>(getSession().getExecutor(), update) {
+
+ @Override
+ protected void handleCompleted() {
+ if (! isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ boolean limitRequired = ! getData().booleanValue();
+ if (limitRequired) {
+
+ final int childCountLimit = getOrInitChildCountLimit(expressionDMC);
+
+ miExpressions.getSubExpressionCount(
+ expressionDMC, childCountLimit + 1,
+ new ViewerDataRequestMonitor<Integer>(getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ int childCount = getData();
+ if (childCountLimit < childCount) {
+ childCount = childCountLimit + 1;
+ }
+
+ update.setChildCount(childCount);
+ update.done();
+ }
+ });
+ } else {
+ GdbVariableVMNode.super.updateElementCountInSessionThread(update);
+ }
+ }
+ });
+
+ return;
+ }
+ }
+
+ super.updateElementCountInSessionThread(update);
+ }
+
+ @Override
+ protected void fillUpdateWithVMCs(IChildrenUpdate update,
+ IDMContext[] dmcs, int firstIndex) {
+ super.fillUpdateWithVMCs(update, dmcs, firstIndex);
+
+ IExpressionDMContext expressionDMC = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressionDMContext.class);
+
+ if (expressionDMC != null) {
+ int childCountLimit = getChildCountLimit(expressionDMC);
+ int childCount = firstIndex + update.getLength();
+ if (childCountLimit < childCount) {
+ update.setChild(new IncompleteChildrenVMC(expressionDMC, childCountLimit), childCountLimit);
+ }
+ }
+ }
+
+ @Override
+ public void update(IPropertiesUpdate[] updates) {
+ List<IPropertiesUpdate> realExpressions = new ArrayList<IPropertiesUpdate>();
+
+ for (IPropertiesUpdate update : updates) {
+ if (update.getElement() instanceof IncompleteChildrenVMC) {
+ if (update.getProperties().contains(
+ AbstractExpressionVMNode.PROP_ELEMENT_EXPRESSION)) {
+ update.setProperty(
+ AbstractExpressionVMNode.PROP_ELEMENT_EXPRESSION,
+ Messages.More_Children);
+
+ }
+
+ if (update.getProperties().contains(PROP_NAME)) {
+ update.setProperty(PROP_NAME, Messages.More_Children);
+ }
+ update.done();
+ } else {
+ realExpressions.add(update);
+ }
+ }
+
+ super.update(realExpressions.toArray(new IPropertiesUpdate[realExpressions.size()]));
+ }
+
+ private int getInitialChildCountLimit() {
+ Object initialLimitProperty = getVMProvider().getPresentationContext().getProperty(
+ IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS);
+
+ return (initialLimitProperty instanceof Integer) ? (Integer) initialLimitProperty
+ : 100;
+ }
+
+ /**
+ * The given expression context requires a child count limit. If a limit
+ * is already available from preceding calls, obtain this limit. Otherwise
+ * calculate the initial value, store it, and return it.
+ *
+ * @param expressionDMC
+ * @return The child count limit to apply for the given expression.
+ *
+ * @since 3.0
+ */
+ protected int getOrInitChildCountLimit(IExpressionDMContext expressionDMC) {
+ if (childCountLimits.containsKey(expressionDMC)) {
+ return childCountLimits.get(expressionDMC);
+ }
+
+ int initialLimit = getInitialChildCountLimit();
+ childCountLimits.put(expressionDMC, initialLimit);
+
+ return initialLimit;
+ }
+
+ /**
+ * @param expressionDMC
+ * @return The currently stored child count limit for the given expression,
+ * or {@link Integer#MAX_VALUE} if no child count limit is currently
+ * stored.
+ *
+ * @since 3.0
+ */
+ protected int getChildCountLimit(IExpressionDMContext expressionDMC) {
+ if (childCountLimits.containsKey(expressionDMC)) {
+ return childCountLimits.get(expressionDMC);
+ }
+ return Integer.MAX_VALUE;
+ }
+
+ private void resetChildCountLimits(IExecutionDMContext execCtx) {
+ int initialLimit = getInitialChildCountLimit();
+ for (IExpressionDMContext limitCtx : childCountLimits.keySet()) {
+ if (DMContexts.isAncestorOf(limitCtx, execCtx)) {
+ childCountLimits.put(limitCtx, initialLimit);
+ }
+ }
+ }
+
+ private void resetAllChildCountLimits() {
+ int initialLimit = getInitialChildCountLimit();
+ for (IExpressionDMContext limitCtx : childCountLimits.keySet()) {
+ childCountLimits.put(limitCtx, initialLimit);
+ }
+ }
+
+ /**
+ * Increment the child count limit by the default increment.
+ * This implementation doubles the current limit.
+ *
+ * @since 3.0
+ */
+ public void incrementChildCountLimit(IExpressionDMContext expressionDMC) {
+ assert(childCountLimits.containsKey(expressionDMC));
+
+ int childCountLimit = getChildCountLimit(expressionDMC);
+ if (childCountLimit < Integer.MAX_VALUE / 2) {
+ childCountLimits.put(expressionDMC, childCountLimit * 2);
+ }
+ }
+
+ @Override
+ public int getDeltaFlags(Object e) {
+ int flags = super.getDeltaFlags(e);
+
+ if (e instanceof FetchMoreChildrenEvent) {
+ flags |= IModelDelta.CONTENT;
+ } else if (e instanceof ISuspendedDMEvent) {
+ // The child count limit must be reset.
+ flags |= IModelDelta.CONTENT;
+ } else if (e instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent)e).getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property))
+ {
+ flags |= IModelDelta.CONTENT;
+ }
+ }
+
+ return flags;
+ }
+
+
+ @Override
+ public int getDeltaFlagsForExpression(IExpression expression, Object event) {
+ int flags = super.getDeltaFlagsForExpression(expression, event);
+
+ if (event instanceof FetchMoreChildrenEvent) {
+ flags |= IModelDelta.CONTENT;
+ } else if (event instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent) event).getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS
+ .equals(property)) {
+ flags |= IModelDelta.CONTENT;
+ }
+ }
+
+ return flags;
+ }
+
+ @Override
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset,
+ RequestMonitor rm) {
+
+ if (e instanceof FetchMoreChildrenEvent) {
+ buildDeltaForFetchMoreChildrenEvent((FetchMoreChildrenEvent) e, parentDelta, rm);
+ return;
+ } else if (e instanceof ISuspendedDMEvent) {
+ resetChildCountLimits(((ISuspendedDMEvent) e).getDMContext());
+ } else if (e instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent)e).getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property))
+ {
+ resetAllChildCountLimits();
+ buildDeltaForChildCountLimitPreferenceChangedEvent(parentDelta, rm);
+ return;
+ }
+ }
+
+ super.buildDelta(e, parentDelta, nodeOffset, rm);
+ }
+
+ @Override
+ public void buildDeltaForExpressionElement(Object element, int elementIdx,
+ Object event, VMDelta parentDelta, RequestMonitor rm) {
+
+ if (event instanceof FetchMoreChildrenEvent) {
+ FetchMoreChildrenEvent fetchMoreEvent = (FetchMoreChildrenEvent) event;
+ GdbVariableExpressionVMC topLevelExpressionVMC = (GdbVariableExpressionVMC) element;
+ if (topLevelExpressionVMC.equals(fetchMoreEvent.getPath().getFirstSegment())) {
+ buildDeltaForFetchMoreChildrenEvent(fetchMoreEvent, parentDelta, rm);
+ return;
+ }
+ } else if (event instanceof ISuspendedDMEvent) {
+ resetChildCountLimits(((ISuspendedDMEvent) event).getDMContext());
+ } else if (event instanceof IContainerSuspendedDMEvent) {
+ resetChildCountLimits(((IContainerSuspendedDMEvent) event).getDMContext());
+ } else if (event instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent)event).getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property))
+ {
+ resetAllChildCountLimits();
+ buildDeltaForChildCountLimitPreferenceChangedEvent(parentDelta, rm);
+ return;
+ }
+ }
+
+ super.buildDeltaForExpressionElement(element, elementIdx, event, parentDelta,
+ rm);
+ }
+
+ private void buildDeltaForFetchMoreChildrenEvent(
+ FetchMoreChildrenEvent fetchMoreChidrenEvent,
+ VMDelta parentDelta, final RequestMonitor rm) {
+
+ TreePath path = fetchMoreChidrenEvent.getPath();
+
+ // Add all the parents of the expression. Those didn't change, however.
+ for (int i = 0; i < path.getSegmentCount() - 2; ++i) {
+ parentDelta = parentDelta.addNode(path.getSegment(i), IModelDelta.NO_CHANGE);
+ }
+
+ // Add the node for the expression. This one changed, of course.
+ final VMDelta expressionDelta =
+ parentDelta.addNode(path.getSegment(path.getSegmentCount() - 2), IModelDelta.CONTENT);
+
+ // Make sure the element formerly know as <...more_children...> is selected
+ // afterwards.
+
+ final int offset = getChildCountLimit(fetchMoreChidrenEvent.getDMContext()) / 2;
+ // The one trailing element is to see whether there are more children.
+ final int maxLength = offset + 1;
+ getVMProvider().updateNode(
+ this,
+ new VMChildrenUpdate(
+ expressionDelta, getVMProvider().getPresentationContext(), offset, maxLength,
+ new DataRequestMonitor<List<Object>>(getExecutor(), rm) {
+ @Override
+ public void handleCompleted() {
+
+ // FIXME if the new child has children they do not appear because of this code.
+// final List<Object> data= getData();
+// if (data != null && data.size() != 0) {
+// expressionDelta.addNode(data.get(0), offset, IModelDelta.SELECT);
+// }
+ rm.done();
+ }
+ })
+ );
+ }
+
+ private void buildDeltaForChildCountLimitPreferenceChangedEvent(
+ final VMDelta parentDelta, final RequestMonitor rm) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ rm.done();
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMProvider.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMProvider.java
index 7df51ff683f..7832b053c30 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMProvider.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMProvider.java
@@ -8,19 +8,34 @@
* Contributors:
* Freescale Semiconductor - initial API and implementation
* Axel Mueller - Bug 306555 - Add support for cast to type / view as array (IExpressions2)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.DsfCastToTypeSupport;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMNode;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMProvider;
+import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
+import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
+import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbVariableVMNode.IncompleteChildrenVMC;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.TreePath;
/**
* A specialization of VariableVMProvider that uses a GDB-specific variable VM
@@ -29,15 +44,39 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont
@SuppressWarnings("restriction")
public class GdbVariableVMProvider extends VariableVMProvider {
+ private IPropertyChangeListener fPreferencesListener;
+
/**
* Constructor (passthru)
*/
public GdbVariableVMProvider(AbstractVMAdapter adapter,
IPresentationContext context, DsfSession session) {
super(adapter, context, session);
+
+ final IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore();
+
+ Integer childCountLimit = store.getInt(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS);
+ if (childCountLimit != 0) {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ childCountLimit);
+ }
+
+ fPreferencesListener = new IPropertyChangeListener() {
+ public void propertyChange(final PropertyChangeEvent event) {
+ handlePropertyChanged(store, event);
+ }};
+ store.addPropertyChangeListener(fPreferencesListener);
}
- /* (non-Javadoc)
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ final IPreferenceStore store = GdbUIPlugin.getDefault().getPreferenceStore();
+ store.removePropertyChangeListener(fPreferencesListener);
+ }
+
+ /* (non-Javadoc)
* @see org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMProvider#configureLayout(org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess)
*/
@Override
@@ -62,4 +101,71 @@ public class GdbVariableVMProvider extends VariableVMProvider {
// provider will recursively drill-down the variable hierarchy.
addChildNodes(subExpressioNode, new IVMNode[] { subExpressioNode });
}
+
+ @Override
+ public void handleEvent(Object event, final RequestMonitor rm) {
+ if (event instanceof DoubleClickEvent && !isDisposed()) {
+
+ final ISelection selection= ((DoubleClickEvent) event).getSelection();
+ if (selection instanceof IStructuredSelection) {
+
+ Object element= ((IStructuredSelection) selection).getFirstElement();
+ if (element instanceof IncompleteChildrenVMC) {
+
+ IncompleteChildrenVMC incompleteChildrenVmc = ((IncompleteChildrenVMC) element);
+ IVMNode node = incompleteChildrenVmc.getVMNode();
+ if (node instanceof GdbVariableVMNode && node.getVMProvider() == this) {
+
+ if (selection instanceof ITreeSelection) {
+
+ ITreeSelection treeSelection = (ITreeSelection) selection;
+ TreePath path = treeSelection.getPaths()[0];
+ IExpressionDMContext exprCtx = incompleteChildrenVmc.getParentDMContext();
+ ((GdbVariableVMNode) node).incrementChildCountLimit(exprCtx);
+
+ // replace double click event with the fetch more children event.
+ final FetchMoreChildrenEvent fetchMoreChildrenEvent = new FetchMoreChildrenEvent(
+ exprCtx, path);
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ handleEvent(fetchMoreChildrenEvent, rm);
+ }
+ });
+
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ super.handleEvent(event, rm);
+ }
+
+ /**
+ * @param store
+ * @param event
+ *
+ * @since 3.0
+ */
+ protected void handlePropertyChanged(final IPreferenceStore store, final PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS.equals(property)) {
+ Integer childCountLimit = store.getInt(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS);
+
+ if (childCountLimit != 0) {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ childCountLimit);
+ } else {
+ getPresentationContext().setProperty(IGdbDebugPreferenceConstants.PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS,
+ null);
+ }
+
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ handleEvent(event);
+ }
+ });
+ }
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Message.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Message.properties
index 3100ae9ddc5..41f5389dc23 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Message.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Message.properties
@@ -7,5 +7,7 @@
#
# Contributors:
# IBM Corporation - initial API and implementation
+# Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
###############################################################################
Internal_Error=Internal Error
+More_Children=<...more children...>
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Messages.java
index 709fa163f3b..a86e0cbd659 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Messages.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/Messages.java
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
@@ -23,4 +24,5 @@ public class Messages extends NLS {
private Messages() {}
public static String Internal_Error;
+ public static String More_Children;
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGdbDebugPreferenceConstants.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGdbDebugPreferenceConstants.java
index d768c7ab2e1..8a62c2731f4 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGdbDebugPreferenceConstants.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGdbDebugPreferenceConstants.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb;
@@ -36,7 +37,21 @@ public interface IGdbDebugPreferenceConstants {
*/
public static final String PREF_USE_INSPECTOR_HOVER = "useInspectorHover"; //$NON-NLS-1$
- /**
+ /**
+ * Boolean preference whether to enable pretty printers for MI variable
+ * objects. Default is <code>true</code>.
+ * @since 4.0
+ */
+ public static final String PREF_ENABLE_PRETTY_PRINTING = "enablePrettyPrinting"; //$NON-NLS-1$
+
+ /**
+ * The maximum limit of children to be initially fetched by GDB for
+ * collections. Default is 100.
+ * @since 4.0
+ */
+ public static final String PREF_INITIAL_CHILD_COUNT_LIMIT_FOR_COLLECTIONS = "initialChildCountLimitForCollections"; //$NON-NLS-1$
+
+ /**
* Help prefixes.
*/
public static final String PREFIX = GdbPlugin.PLUGIN_ID + "."; //$NON-NLS-1$
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java
index aee4ba769d1..f96fb0e68b4 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java
@@ -9,6 +9,7 @@
* Ericsson - initial API and implementation
* Nokia - create and use backend service.
* IBM Corporation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.launching;
@@ -27,6 +28,7 @@ import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.actions.IConnect;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
@@ -44,6 +46,7 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin;
@@ -76,6 +79,7 @@ public class FinalLaunchSequence extends ReflectionSequence {
"stepInitializeFinalLaunchSequence", //$NON-NLS-1$
"stepSetEnvironmentDirectory", //$NON-NLS-1$
"stepSetBreakpointPending", //$NON-NLS-1$
+ "stepEnablePrettyPrinting", //$NON-NLS-1$
"stepSourceGDBInitFile", //$NON-NLS-1$
"stepSetEnvironmentVariables", //$NON-NLS-1$
"stepSetExecutable", //$NON-NLS-1$
@@ -182,6 +186,29 @@ public class FinalLaunchSequence extends ReflectionSequence {
}
/**
+ * Turn on pretty printers for MI variable objects, if enabled in preferences.
+ * Also, turn off error messages from python, all the time.
+ * @since 4.0
+ */
+ @Execute
+ public void stepEnablePrettyPrinting(final RequestMonitor requestMonitor) {
+ if (Platform.getPreferencesService().getBoolean("org.eclipse.cdt.dsf.gdb.ui", //$NON-NLS-1$
+ IGdbDebugPreferenceConstants.PREF_ENABLE_PRETTY_PRINTING,
+ false, null)) {
+
+ fCommandControl.enablePrettyPrintingForMIVariableObjects(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleCompleted() {
+ fCommandControl.setPrintPythonErrors(false, requestMonitor);
+ }
+ });
+ } else {
+ fCommandControl.setPrintPythonErrors(false, requestMonitor);
+ }
+ }
+
+ /**
* Source the gdbinit file specified in the launch.
* @since 4.0
*/
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java
index 442b9294bb2..061b34cc4ec 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java
@@ -10,6 +10,7 @@
* Ericsson - Modified for additional features in DSF Reference implementation
* Nokia - create and use backend service.
* Vladimir Prus (CodeSourcery) - Support for -data-read-memory-bytes (bug 322658)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service.command;
@@ -609,4 +610,18 @@ public class GDBControl extends AbstractMIControl implements IGDBControl {
public List<String> getFeatures() {
return fFeatures;
}
+
+ /**
+ * @since 4.0
+ */
+ public void enablePrettyPrintingForMIVariableObjects(RequestMonitor rm) {
+ rm.done();
+ }
+
+ /**
+ * @since 4.0
+ */
+ public void setPrintPythonErrors(boolean enabled, RequestMonitor rm) {
+ rm.done();
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java
index 935b3c47ff4..cdfdc6958f4 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java
@@ -10,6 +10,7 @@
* Ericsson - Modified for additional features in DSF Reference implementation
* Ericsson - New version for 7_0
* Vladimir Prus (CodeSourcery) - Support for -data-read-memory-bytes (bug 322658)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service.command;
@@ -783,4 +784,27 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
requestMonitor.done();
}
}
+
+ /**
+ * @since 4.0
+ */
+ public void enablePrettyPrintingForMIVariableObjects(
+ final RequestMonitor rm) {
+
+ queueCommand(
+ getCommandFactory().createMIEnablePrettyPrinting(fControlDmc),
+ new DataRequestMonitor<MIInfo>(getExecutor(), rm));
+ }
+
+ /**
+ * @since 4.0
+ */
+ public void setPrintPythonErrors(boolean enabled, RequestMonitor rm) {
+
+ String subCommand = "set python print-stack " + (enabled ? "on" : "off"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+
+ queueCommand(
+ getCommandFactory().createCLIMaintenance(fControlDmc, subCommand),
+ new DataRequestMonitor<MIInfo>(getExecutor(), rm));
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java
index 02ecee9aa84..bccf575377d 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java
@@ -8,6 +8,7 @@
* Contributors:
* Ericsson - initial API and implementation
* Vladimir Prus (CodeSourcery) - Support for -data-read-memory-bytes (bug 322658)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service.command;
@@ -66,4 +67,25 @@ public interface IGDBControl extends IMICommandControl {
* @since 4.0
*/
List<String> getFeatures();
+
+ /**
+ * Enable the pretty printers also for MI variable objects. This basically
+ * sends -enable-pretty-printing.
+ *
+ * @param rm
+ *
+ * @since 4.0
+ */
+ void enablePrettyPrintingForMIVariableObjects(RequestMonitor rm);
+
+ /**
+ * Turns the printing of python errors on or off.
+ *
+ * @param enabled
+ * If <code>true</code>, printing errors is turned on.
+ * @param rm
+ *
+ * @since 4.0
+ */
+ void setPrintPythonErrors(boolean enabled, RequestMonitor rm);
} \ No newline at end of file
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/IMIExpressions.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/IMIExpressions.java
new file mode 100644
index 00000000000..7baf0a1df77
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/IMIExpressions.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.mi.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IExpressions3;
+
+/**
+ * An extension of {@link IExpressions} which became necessary because the MI
+ * implementation of {@link IExpressions} has problems if asked for all
+ * sub-expressions. Problems may arise if uninitialized data objects are
+ * inspected. In the worst case, pretty printers may run into endless loops
+ * (e.g. linked list that become cycle), and gdb never returns. But also in the
+ * normal case of uninitialized collections, you easily end up with millions of
+ * useless elements, damaging the responsiveness of the workbench.
+ *
+ * In order to avoid those problems, this extension lets the client specify a
+ * maximum number of children that it is interested in.
+ *
+ * If you have an instance implementing {@link IExpressions}, you should always
+ * check whether it implements this extension, and if so, use the methods of the
+ * extension.
+ *
+ * @since 4.0
+ */
+public interface IMIExpressions extends IExpressions3 {
+
+ /**
+ * A special constant that can be used in methods that expect a child count
+ * limit. If this constant is passed, the implementation will use the most
+ * recent child count limit for the expression. If such a limit was never
+ * specified before, at least one child will be fetched in order to tell
+ * whether an expression has children or not.
+ */
+ public static final int CHILD_COUNT_LIMIT_UNSPECIFIED = -1;
+
+ /**
+ * This method indicates whether the given expression can safely be asked
+ * for all its sub-expressions.
+ *
+ * If this method returns <code>false</code>, this has the following impact:
+ * <ul>
+ * <li>you should not call
+ * {@link IExpressions#getSubExpressionCount(IExpressionDMContext, DataRequestMonitor)},
+ * but
+ * {@link IMIExpressions#getSubExpressionCount(IExpressionDMContext, int, DataRequestMonitor)}
+ * instead.</li>
+ *
+ * <li>you should not call
+ * {@link IExpressions#getSubExpressions(IExpressionDMContext, DataRequestMonitor)},
+ * but
+ * {@link IExpressions#getSubExpressions(IExpressionDMContext, int, int, DataRequestMonitor)}
+ * </li>
+ * </ul>
+ *
+ * @param exprCtx
+ * The data model context representing an expression.
+ *
+ * @param rm
+ * Data Request monitor containing <code>true</code> if this expression can
+ * safely fetch all its sub-expressions. <code>false</false> otherwise.
+ */
+ public void safeToAskForAllSubExpressions(IExpressionDMContext exprCtx,
+ DataRequestMonitor<Boolean> rm);
+
+ /**
+ * This method is the same as
+ * {@link IExpressions#getSubExpressionCount(org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext, DataRequestMonitor)}
+ * , with the slight but important difference that this method allows to
+ * provide an upper limit of children we are interested in.
+ * As long as {@link #safeToAskForAllSubExpressions(org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext, DataRequestMonitor)}
+ * returns true, the original method can be called, and this method is not of further interest.
+ * However, if {@link #safeToAskForAllSubExpressions(org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext, DataRequestMonitor)}
+ * returns false, the original method must not be called, and this method must instead be used.
+ * Otherwise, the gdb response time may be very slow, or it even may hang.
+ *
+ * @param exprCtx
+ * The data model context representing an expression.
+ *
+ * @param maxNumberOfChildren
+ * The implementation needs not check whether there are more than
+ * this number of children. However, if the implementation has
+ * already knowledge of more children than this, or can obtain
+ * them equally efficient, it might also return a higher count.
+ *
+ * @param rm
+ * Request completion monitor containing the number of
+ * sub-expressions of the specified expression
+ */
+ void getSubExpressionCount(IExpressionDMContext exprCtx,
+ int maxNumberOfChildren, DataRequestMonitor<Integer> rm);
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
index 6f55564fad2..036fd2f30d9 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
@@ -7,8 +7,9 @@
*
* Contributors:
* Wind River Systems - initial API and implementation
- * Ericsson - Modified for handling of multiple execution contexts
+ * Ericsson - Modified for handling of multiple execution contexts
* Axel Mueller - Bug 306555 - Add support for cast to type / view as array (IExpressions2)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
@@ -26,7 +27,6 @@ import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions2;
-import org.eclipse.cdt.dsf.debug.service.IExpressions3;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
@@ -68,7 +68,7 @@ import org.osgi.framework.BundleContext;
*
* @since 2.0
*/
-public class MIExpressions extends AbstractDsfService implements IExpressions3, ICachingService {
+public class MIExpressions extends AbstractDsfService implements IMIExpressions, ICachingService {
/**
* A format that gives more details about an expression and supports pretty-printing
@@ -93,12 +93,28 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
public static class ExpressionInfo {
private final String fullExpression;
private final String relativeExpression;
-
+ private boolean isDynamic = false;
+ private ExpressionInfo parent;
+ private int indexInParent = -1;
+ private int childCountLimit = IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED;
+
public ExpressionInfo(String full, String relative) {
fullExpression = full;
relativeExpression = relative;
}
-
+
+ /**
+ * @since 4.0
+ */
+ public ExpressionInfo(String full, String relative, boolean isDynamic,
+ ExpressionInfo parent, int indexInParent) {
+ fullExpression = full;
+ relativeExpression = relative;
+ this.isDynamic = isDynamic;
+ this.parent = parent;
+ this.indexInParent = indexInParent;
+ }
+
public String getFullExpr() { return fullExpression; }
public String getRelExpr() { return relativeExpression; }
@@ -109,6 +125,7 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
fullExpression.equals(((ExpressionInfo) other).fullExpression)) {
if (relativeExpression == null ? ((ExpressionInfo) other).relativeExpression == null :
relativeExpression.equals(((ExpressionInfo) other).relativeExpression)) {
+ // The other members don't play any role for equality.
return true;
}
}
@@ -120,13 +137,98 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
public int hashCode() {
return (fullExpression == null ? 0 : fullExpression.hashCode()) ^
(relativeExpression == null ? 0 : relativeExpression.hashCode());
+ // The other members don't play any role for equality.
}
@Override
public String toString() {
- return "[" + fullExpression +", " + relativeExpression + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ return "[" + fullExpression +", " + relativeExpression + ", isDynamic=" + isDynamic + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$
}
+
+ /**
+ * @return The parent expression info, if existing.
+ * @since 4.0
+ */
+ public ExpressionInfo getParent() {
+ return parent;
+ }
+
+ /**
+ * @return The index in the child array of the parent. Only valid if
+ * {@link #getParent()} returns not null.
+ * @since 4.0
+ */
+ public int getIndexInParentExpression() {
+ return indexInParent;
+ }
+
+ /**
+ * @return Whether the corresponding variable object is dynamic,
+ * i.e. it's value and children are provided by a pretty printer.
+ * @since 4.0
+ */
+ public boolean isDynamic() {
+ return isDynamic;
+ }
+
+ /**
+ * @return Whether the expression info has any ancestor that is dynamic.
+ * @since 4.0
+ */
+ public boolean hasDynamicAncestor() {
+ for (ExpressionInfo parent = getParent(); parent != null; parent = parent.getParent()) {
+ if (parent.isDynamic()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param isDynamic
+ * Whether the value and children of this expression is
+ * currently provided by a pretty printer or not.
+ * @since 4.0
+ */
+ public void setDynamic(boolean isDynamic) {
+ this.isDynamic = isDynamic;
+ }
+
+ /**
+ * @param parent The new parent expression info.
+ * @since 4.0
+ */
+ public void setParent(ExpressionInfo parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @param index The index in the children array of the parent.
+ * @since 4.0
+ */
+ public void setIndexInParent(int index) {
+ this.indexInParent = index;
+ }
+
+ /**
+ * @return The current limit on the number of children to be fetched.
+ * @since 4.0
+ */
+ public int getChildCountLimit() {
+ return childCountLimit;
+ }
+
+ /**
+ * @param newLimit
+ * The new limit on the number of children to be fetched.
+ * @since 4.0
+ */
+ public void setChildCountLimit(int newLimit) {
+ this.childCountLimit = newLimit;
+ }
}
+
/**
* This class represents an expression.
*/
@@ -188,8 +290,32 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
}
private MIExpressionDMC(String sessionId, String expr, String relExpr, IDMContext parent) {
+ this(sessionId, new ExpressionInfo(expr, relExpr), parent);
+ }
+
+ /**
+ * ExpressionDMC Constructor for expression to be evaluated in context
+ * of a stack frame.
+ *
+ * @param sessionId
+ * The session ID in which this context is created.
+ * @param info
+ * The expression info that this expression is to use.
+ * @param frameCtx
+ * The parent stack frame context for this ExpressionDMC.
+ *
+ * @since 4.0
+ */
+ public MIExpressionDMC(String sessionId, ExpressionInfo info, IFrameDMContext frameCtx) {
+ this(sessionId, info, (IDMContext)frameCtx);
+ }
+
+ /**
+ * @since 4.0
+ */
+ private MIExpressionDMC(String sessionId, ExpressionInfo info, IDMContext parent) {
super(sessionId, new IDMContext[] { parent });
- exprInfo = new ExpressionInfo(expr, relExpr);
+ exprInfo = info;
}
/**
@@ -232,6 +358,26 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
public String getRelativeExpression() {
return exprInfo.getRelExpr();
}
+
+ /**
+ * @return Get the expression info for this context.
+ * @since 4.0
+ */
+ public ExpressionInfo getExpressionInfo() {
+ return exprInfo;
+ }
+
+ /**
+ * @param info
+ *
+ * @since 4.0
+ */
+ public void setExpressionInfo(ExpressionInfo info) {
+ assert (this.exprInfo.getFullExpr().equals(info.getFullExpr()));
+ assert (this.exprInfo.getRelExpr().equals(info.getRelExpr()));
+
+ this.exprInfo = info;
+ }
}
protected static class InvalidContextExpressionDMC extends AbstractDMContext
@@ -313,7 +459,27 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
return (fAddr == null ? "null" : "(" + fAddr.toHexAddressString()) + ", " + fSize + ")"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
}
}
+
+ /**
+ * If an expressions doesn't have an address, or it cannot be determined,
+ * use this class.
+ * @since 4.0
+ */
+ protected class InvalidDMAddress implements IExpressionDMLocation {
+ public IAddress getAddress() {
+ return IExpressions.IExpressionDMLocation.INVALID_ADDRESS;
+ }
+
+ public int getSize() {
+ return 0;
+ }
+
+ public String getLocation() {
+ return ""; //$NON-NLS-1$
+ }
+ }
+
/**
* This class represents the static data referenced by an instance of ExpressionDMC,
* such as its type and number of children; it does not contain the value or format
@@ -552,8 +718,6 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
* This method shuts down this service. It unregisters the service, stops
* receiving service events, and calls the superclass shutdown() method to
* finish the shutdown process.
- *
- * @return void
*/
@Override
public void shutdown(RequestMonitor requestMonitor) {
@@ -582,9 +746,18 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
* Create an expression context.
*/
public IExpressionDMContext createExpression(IDMContext ctx, String expression, String relExpr) {
+ return createExpression(ctx, new ExpressionInfo(expression, relExpr));
+ }
+
+ /**
+ * Create an expression context from a given expression info.
+ * @since 4.0
+ */
+ private IExpressionDMContext createExpression(IDMContext ctx, ExpressionInfo info) {
+ String expression = info.getFullExpr();
IFrameDMContext frameDmc = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class);
if (frameDmc != null) {
- return new MIExpressionDMC(getSession().getId(), expression, relExpr, frameDmc);
+ return new MIExpressionDMC(getSession().getId(), info, frameDmc);
}
IMIExecutionDMContext execCtx = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class);
@@ -595,7 +768,7 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
MIStack stackService = getServicesTracker().getService(MIStack.class);
if (stackService != null) {
frameDmc = stackService.createFrameDMContext(execCtx, 0);
- return new MIExpressionDMC(getSession().getId(), expression, relExpr, frameDmc);
+ return new MIExpressionDMC(getSession().getId(), info, frameDmc);
}
return new InvalidContextExpressionDMC(getSession().getId(), expression, execCtx);
@@ -603,7 +776,7 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
IMemoryDMContext memoryCtx = DMContexts.getAncestorOfType(ctx, IMemoryDMContext.class);
if (memoryCtx != null) {
- return new MIExpressionDMC(getSession().getId(), expression, relExpr, memoryCtx);
+ return new MIExpressionDMC(getSession().getId(), info, memoryCtx);
}
// Don't care about the relative expression at this point
@@ -662,7 +835,8 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
fExpressionCache.execute(
new ExprMetaGetVar(dmc),
new DataRequestMonitor<ExprMetaGetVarInfo>(getExecutor(), rm) {
- @Override
+
+ @Override
protected void handleSuccess() {
IExpressionDMData.BasicType basicType = null;
@@ -682,7 +856,10 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
break;
case GDBType.GENERIC:
default:
- if (getData().getNumChildren() > 0) {
+ // The interesting question is not hasChildren,
+ // but canHaveChildren. E.g. an empty
+ // collection still is a composite.
+ if (getData().hasChildren() || getData().getCollectionHint()) {
basicType = IExpressionDMData.BasicType.composite;
} else {
basicType = IExpressionDMData.BasicType.basic;
@@ -718,6 +895,17 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
IExpressionDMContext dmc,
final DataRequestMonitor<IExpressionDMAddress> rm) {
+ if (dmc instanceof MIExpressionDMC) {
+ MIExpressionDMC miDMC = (MIExpressionDMC) dmc;
+ if (miDMC.getExpressionInfo().hasDynamicAncestor()) {
+ // For children of dynamic varobjs, there is no full expression that gdb
+ // could evaluate in order to provide address and size.
+ rm.setData(new InvalidDMAddress());
+ rm.done();
+ return;
+ }
+ }
+
// First create an address expression and a size expression
// to be used in back-end calls
final IExpressionDMContext addressDmc =
@@ -778,37 +966,45 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
{
// We need to make sure the FormattedValueDMContext also holds an ExpressionContext,
// or else this method cannot do its work.
- // Note that we look for MIExpressionDMC and not IExpressionDMC, because getting
+ // Note that we look for MIExpressionDMC and not IExpressionDMC, because
// looking for IExpressionDMC could yield InvalidContextExpressionDMC which is still
- // not what we need to have.
+ // not what we need.
MIExpressionDMC exprDmc = DMContexts.getAncestorOfType(dmc, MIExpressionDMC.class);
if (exprDmc == null ) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$
rm.done();
} else {
if (DETAILS_FORMAT.equals(dmc.getFormatID())) {
- // This format is obtained through a different GDB command.
- // It yields more details than the variableObject output.
- // Starting with GDB 7.0, this format automatically supports pretty-printing, as long as
- // GDB has been configured to support it.
- fExpressionCache.execute(
- fCommandFactory.createMIDataEvaluateExpression(exprDmc),
- new DataRequestMonitor<MIDataEvaluateExpressionInfo>(getExecutor(), rm) {
- @Override
- protected void handleSuccess() {
- rm.setData(new FormattedValueDMData(getData().getValue()));
- rm.done();
- }
- @Override
- protected void handleError() {
- if (fTraceVisualization) {
- rm.setData(new FormattedValueDMData("")); //$NON-NLS-1$
- rm.done();
- } else {
- super.handleError();
- }
- }
- });
+ if (exprDmc.getExpressionInfo().hasDynamicAncestor()) {
+ // -data-evaluate-expression does not work for children of
+ // dynamic varobjs, since there is no full expression
+ // that gdb could evaluate.
+ rm.setData(new FormattedValueDMData(Messages.MIExpressions_NotAvailableBecauseChildOfDynamicVarobj));
+ rm.done();
+ } else {
+ // This format is obtained through a different GDB command.
+ // It yields more details than the variableObject output.
+ // Starting with GDB 7.0, this format automatically supports pretty-printing, as long as
+ // GDB has been configured to support it.
+ fExpressionCache.execute(
+ fCommandFactory.createMIDataEvaluateExpression(exprDmc),
+ new DataRequestMonitor<MIDataEvaluateExpressionInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(new FormattedValueDMData(getData().getValue()));
+ rm.done();
+ }
+ @Override
+ protected void handleError() {
+ if (fTraceVisualization) {
+ rm.setData(new FormattedValueDMData("")); //$NON-NLS-1$
+ rm.done();
+ } else {
+ super.handleError();
+ }
+ }
+ });
+ }
} else {
fExpressionCache.execute(
new ExprMetaGetValue(dmc),
@@ -838,7 +1034,7 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
/**
* Retrieves the children expressions of the specified expression
*
- * @param exprCtx
+ * @param dmc
* The context for the expression for which the children
* should be retrieved.
* @param rm
@@ -857,9 +1053,7 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
IExpressionDMContext[] childArray = new IExpressionDMContext[childrenExpr.length];
for (int i=0; i<childArray.length; i++) {
childArray[i] = createExpression(
- dmc.getParents()[0],
- childrenExpr[i].getFullExpr(),
- childrenExpr[i].getRelExpr());
+ dmc.getParents()[0], childrenExpr[i]);
}
rm.setData(childArray);
@@ -890,7 +1084,7 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
* @param rm
* The data request monitor that will contain the requested data
*/
- public void getSubExpressions(IExpressionDMContext exprCtx, final int startIndex,
+ public void getSubExpressions(final IExpressionDMContext exprCtx, final int startIndex,
final int length, final DataRequestMonitor<IExpressionDMContext[]> rm) {
if (startIndex < 0 || length < 0) {
@@ -900,28 +1094,27 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
}
if (exprCtx instanceof MIExpressionDMC) {
- getSubExpressions(
- exprCtx,
- new DataRequestMonitor<IExpressionDMContext[]>(getExecutor(), rm) {
+ fExpressionCache.execute(
+ new ExprMetaGetChildren(exprCtx, startIndex + length),
+ new DataRequestMonitor<ExprMetaGetChildrenInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
- IExpressionDMContext[] subExpressions = getData();
+ ExpressionInfo[] childrenExpr = getData().getChildrenExpressions();
- if (startIndex >= subExpressions.length) {
+ if (startIndex >= childrenExpr.length) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$
rm.done();
return;
}
-
- int realLength = length;
- if (startIndex + length > subExpressions.length) {
- realLength = subExpressions.length - startIndex;
- }
-
- IExpressionDMContext[] subRange = new IExpressionDMContext[realLength];
- System.arraycopy(subExpressions, startIndex, subRange, 0, realLength);
- rm.setData(subRange);
+ int numChildren = childrenExpr.length - startIndex;
+ numChildren = Math.min(length, numChildren);
+ IExpressionDMContext[] childrenArray = new IExpressionDMContext[numChildren];
+ for (int i=0; i < numChildren; i++) {
+ childrenArray[i] = createExpression(
+ exprCtx.getParents()[0], childrenExpr[startIndex + i]);
+ }
+ rm.setData(childrenArray);
rm.done();
}
});
@@ -935,20 +1128,40 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
}
/**
- * Retrieves the count of children expressions of the specified expression
- *
- * @param exprCtx
- * The context for the expression for which the children count
- * should be retrieved.
- * @param rm
- * The data request monitor that will contain the requested data
+ * @since 4.0
+ */
+ public void safeToAskForAllSubExpressions(IExpressionDMContext dmc,
+ final DataRequestMonitor<Boolean> rm) {
+ if (dmc instanceof MIExpressionDMC) {
+ fExpressionCache.execute(
+ new ExprMetaGetVar(dmc),
+ new DataRequestMonitor<ExprMetaGetVarInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ boolean safe = getData().isSafeToAskForAllChildren();
+
+ rm.setData(safe);
+ rm.done();
+ }
+ });
+ } else if (dmc instanceof InvalidContextExpressionDMC) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$
+ rm.done();
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ /**
+ * @since 4.0
*/
public void getSubExpressionCount(IExpressionDMContext dmc,
- final DataRequestMonitor<Integer> rm)
- {
+ final int numChildLimit, final DataRequestMonitor<Integer> rm) {
+
if (dmc instanceof MIExpressionDMC) {
fExpressionCache.execute(
- new ExprMetaGetChildCount(dmc),
+ new ExprMetaGetChildCount(dmc, numChildLimit),
new DataRequestMonitor<ExprMetaGetChildCountInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
@@ -964,13 +1177,28 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
rm.done();
}
}
+
+ /**
+ * Retrieves the count of children expressions of the specified expression
+ *
+ * @param dmc
+ * The context for the expression for which the children count
+ * should be retrieved.
+ * @param rm
+ * The data request monitor that will contain the requested data
+ */
+ public void getSubExpressionCount(IExpressionDMContext dmc,
+ final DataRequestMonitor<Integer> rm)
+ {
+ getSubExpressionCount(dmc, IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED, rm);
+ }
/**
* This method indicates if an expression can be written to.
*
- * @param dmc: The data model context representing an expression.
+ * @param dmc The data model context representing an expression.
*
- * @param rm: Data Request monitor containing True if this expression's value can be edited. False otherwise.
+ * @param rm Data Request monitor containing True if this expression's value can be edited. False otherwise.
*/
public void canWriteExpression(IExpressionDMContext dmc, final DataRequestMonitor<Boolean> rm) {
@@ -997,7 +1225,7 @@ public class MIExpressions extends AbstractDsfService implements IExpressions3,
/**
* Changes the value of the specified expression based on the new value and format.
*
- * @param expressionContext
+ * @param dmc
* The context for the expression for which the value
* should be changed.
* @param expressionValue
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
index 68cad5a05c7..c35f1fcf4b9 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
@@ -11,6 +11,7 @@
* Ericsson - Major updates for GDB/MI implementation
* Ericsson - Major re-factoring to deal with children
* Axel Mueller - Bug 306555 - Add support for cast to type / view as array (IExpressions2)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
@@ -63,6 +64,9 @@ import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetChildCountInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetChildrenInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetValueInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetVarInfo;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIDisplayHint;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIDisplayHint.GdbDisplayHint;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIVar;
import org.eclipse.cdt.dsf.mi.service.command.output.MIVarAssignInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIVarChange;
@@ -183,10 +187,127 @@ import org.eclipse.core.runtime.Status;
* Note that versions of GDB after 6.7 will allows to issue -var-evaluate-expression
* with a specified format, therefore allowing us to never use -var-set-format, and
* consequently, to easily keep the display format of all variable objects to natural.
+ *
+ * Notes on Dynamic Variable Objects (varobj)
+ * ------------------------------------------
+ * - with version 7.0, gdb support so-called pretty printers.
+ *
+ * - pretty printers are registered for certain types
+ *
+ * - if there is a pretty printer registered for the type of a variable,
+ * the pretty printer provides the value and the children of that variable
+ *
+ * - a varobj whose value and/or children are provided by a pretty printer,
+ * are referred to as dynamic variable objects
+ *
+ * - dynamic varobjs change the game: it's not wise to ask it about all its
+ * children, not even the number of children it has. The reason is that
+ * in order to find out about the number of children the pretty printer
+ * must fetch all the children from the inferiors memory. If the variable
+ * is not yet initialized, the set of children are random, and thus might
+ * be huge. Even worse, there are data structures where fetching all
+ * children may result in an endless loop. The Eclipse debugger then hangs.
+ *
+ * - In order to avoid this, we will always fetch up to a certain maximum
+ * number of children. Furthermore, it is possible to find out whether there
+ * are more children available. In the UI, all the currently fetched
+ * children are available. In addition, if there are more children
+ * available, a special node will be appended to indicate that there is
+ * more the user could fetch.
+ *
+ * - Dynamic varobjs can change their value, as leaf varobjs can do.
+ * Especially, children can be added or removed during an update.
+ *
+ * - There is no expression for children of dynamic varobjs (at least not
+ * yet, http://sourceware.org/bugzilla/show_bug.cgi?id=10252 would fix that).
+ * The reason -var-info-path-expression returns garbage for children of
+ * dynamic varobjs.
+ *
+ * - Because of this, the variable of an expression that is a child of
+ * a dynamic varobj cannot be created again using -var-create, once
+ * the LRU cache has deleted it. Instead, we track the parent and index
+ * within this parent for each non-root variable, and later use
+ * -var-list-children parent indexInParent (indexInParent + 1)
+ * in order to create the MI variable anew.
+ *
+ * - The fetching of children for dynamic varobjs becomes a bit more complicated.
+ * For the traditional varobjs, once children where requested, all children
+ * were fetched. For dynamic varobjs, we can no longer fetch all children.
+ * Instead, the client will provide a maximum number of children that
+ * is to be fetched. Every time the child count or children are requested,
+ * we must check whether there are additional children to be fetched,
+ * because the limit might have extended.
+ * Fetching additional children can only be done by one request monitor at a time.
+ * The serialization of the request monitors is done in getChildren by
+ * ensuring that fetchChildren is called for one request monitor at a time.
+ * fetchChildren in turn checks whether enough children are fetched, and
+ * if not, fetches the additional children.
*/
public class MIVariableManager implements ICommandControl {
+ /**
+ * Stores the information about children of a variable object.
+ *
+ * @since 4.0
+ */
+ protected static class ChildrenInfo {
+ private final ExpressionInfo[] children;
+ private final boolean hasMore;
+
+ public ChildrenInfo(ExpressionInfo[] children, boolean hasMore) {
+ this.children = children;
+ this.hasMore = hasMore;
+ }
+ /**
+ * @return The currently fetched children. Ask {@link #hasMore()} in
+ * order to find out whether there are more to fetch.
+ */
+ public ExpressionInfo[] getChildren() {
+ return children;
+ }
+
+ /**
+ * @return true, if there are more than just those returned by
+ * {@link #getChildren()}.
+ */
+ public boolean hasMore() {
+ return hasMore;
+ }
+ }
+
+ /**
+ * Stores the information about the children count of a variable object.
+ *
+ * @since 4.0
+ */
+ protected static class ChildrenCountInfo {
+ private final int childrenCount;
+ private final boolean hasMore;
+
+ public ChildrenCountInfo(int childrenCount, boolean hasMore) {
+ this.childrenCount = childrenCount;
+ this.hasMore = hasMore;
+ }
+
+ /**
+ * The number of children that we currently know of. Ask
+ * {@link #hasMore()} in order to find out whether there is at least one
+ * more.
+ */
+ public int getChildrenCount() {
+ return childrenCount;
+ }
+
+ /**
+ * @return <code>true</code> if there are more children than actually
+ * returned by {@link #getChildrenCount()}.
+ */
+ public boolean hasMore() {
+ return hasMore;
+ }
+ }
+
/**
* Utility class to track the progress and information of MI variable objects
*/
@@ -195,6 +316,12 @@ public class MIVariableManager implements ICommandControl {
// Don't use an enumeration to allow subclasses to extend this
protected static final int STATE_READY = 0;
protected static final int STATE_UPDATING = 1;
+ /** @since 4.0 */
+ protected static final int STATE_NOT_CREATED = 10;
+ /** @since 4.0 */
+ protected static final int STATE_CREATING = 11;
+ /** @since 4.0 */
+ protected static final int STATE_CREATION_FAILED = 12;
protected int currentState;
@@ -211,7 +338,9 @@ public class MIVariableManager implements ICommandControl {
private String format = IFormattedValues.NATURAL_FORMAT;
// The full expression that can be used to characterize this object
- private String fullExp = null;
+ // plus some other information that shall live longer than the
+ // MIVariableObject.
+ private ExpressionInfo exprInfo;
private String type = null;
private GDBType gdbType;
// A hint at the number of children. This value is obtained
@@ -228,11 +357,16 @@ public class MIVariableManager implements ICommandControl {
// A queue of request monitors that requested an update
protected LinkedList<DataRequestMonitor<Boolean>> updatesPending;
+
+ /** @since 4.0 */
+ protected LinkedList<DataRequestMonitor<ChildrenInfo>> fetchChildrenPending;
- // The relative expressions of the children of this variable, if any.
+ // The children of this variable, if any.
// Null means we didn't fetch them yet, while an empty array means no children
private ExpressionInfo[] children = null;
-
+ private boolean hasMore = false;
+ private MIDisplayHint displayHint = MIDisplayHint.NONE;
+
// The parent of this variable object within GDB. Null if this object has no parent
private MIVariableObject parent = null;
@@ -241,12 +375,21 @@ public class MIVariableManager implements ICommandControl {
private MIRootVariableObject rootToUpdate = null;
protected boolean outOfScope = false;
-
+
+ private boolean fetchingChildren = false;
+
public MIVariableObject(VariableObjectId id, MIVariableObject parentObj) {
- currentState = STATE_READY;
+ this(id, parentObj, false);
+ }
+
+ /** @since 4.0 */
+ public MIVariableObject(VariableObjectId id, MIVariableObject parentObj,
+ boolean needsCreation) {
+ currentState = needsCreation ? STATE_NOT_CREATED : STATE_READY;
operationsPending = new LinkedList<RequestMonitor>();
updatesPending = new LinkedList<DataRequestMonitor<Boolean>>();
+ fetchChildrenPending = new LinkedList<DataRequestMonitor<ChildrenInfo>>();
internalId = id;
setParent(parentObj);
@@ -262,8 +405,48 @@ public class MIVariableManager implements ICommandControl {
public MIVariableObject getParent() { return parent; }
public MIRootVariableObject getRootToUpdate() { return rootToUpdate; }
- public String getExpression() { return fullExp; }
+ public String getExpression() { return exprInfo.getFullExpr(); }
public String getType() { return type; }
+
+ /**
+ * @since 4.0
+ */
+ public ExpressionInfo getExpressionInfo() { return exprInfo; }
+
+ /**
+ * @return <code>true</code> if value and children of this varobj are
+ * currently provided by a pretty printer.
+ *
+ * @since 4.0
+ */
+ public boolean isDynamic() { return exprInfo.isDynamic(); }
+
+ /**
+ * @return For dynamic varobjs ({@link #isDynamic() returns true}) this
+ * method returns whether there are children in addition to the
+ * currently fetched, i.e. whether there are more children than
+ * {@link #getNumChildrenHint()} returns.
+ *
+ * @since 4.0
+ */
+ public boolean hasMore() { return hasMore; }
+
+ /**
+ * @since 4.0
+ */
+ public MIDisplayHint getDisplayHint() { return displayHint; };
+
+ /**
+ * @since 4.0
+ */
+ protected void setDisplayHint(MIDisplayHint displayHint) {
+ this.displayHint = displayHint;
+ };
+
+ /**
+ * @since 4.0
+ */
+ public boolean hasChildren() { return (getNumChildrenHint() != 0 || hasMore()); }
/** @since 3.0 */
public GDBType getGDBType() { return gdbType; }
@@ -275,7 +458,8 @@ public class MIVariableManager implements ICommandControl {
* Use <code>isNumChildrenHintTrustworthy()</code> to know if the
* hint can be trusted.
*
- * Note that a hint of 0 children can always be trusted.
+ * Note that a hint of 0 children can always be trusted, except for
+ * <code>{@link #hasMore} == true</code>.
*
* @since 3.0 */
public int getNumChildrenHint() { return numChildrenHint; }
@@ -296,7 +480,7 @@ public class MIVariableManager implements ICommandControl {
// -var-info-expression. Do we have to use -var-info-expression for each
// variable object, or can we do it one time only for the whole program?
// Right now, we always assume we could be using C++
- return (getNumChildrenHint() == 0 || isArray());
+ return ((getNumChildrenHint() == 0 && ! hasMore()) || isArray());
}
public String getValue(String format) { return valueMap.get(format); }
@@ -310,16 +494,74 @@ public class MIVariableManager implements ICommandControl {
// A complex variable is one with children. However, it must not be a pointer since a pointer
// does have children, but is still a 'simple' variable, as it can be modifed.
// Note that the numChildrenHint can be trusted when asking if the number of children is 0 or not
- public boolean isComplex() { return (getGDBType() == null) ? false : getGDBType().getType() != GDBType.POINTER && getNumChildrenHint() > 0; }
+ public boolean isComplex() {
+ return (getGDBType() == null) ? false
+ : getGDBType().getType() != GDBType.POINTER
+ && (getNumChildrenHint() > 0
+ || hasMore() || getDisplayHint().isCollectionHint());
+ }
+
+ /**
+ * @return Whether this varobj can safely be asked for all its children.
+ *
+ * @since 4.0
+ */
+ public boolean isSafeToAskForAllChildren() {
+ GdbDisplayHint displayHint = getDisplayHint().getGdbDisplayHint();
+
+ // Here we balance usability against a slight risk of instability:
+ //
+ // Usability: if you have a class/struct-like pretty printer
+ // all children are fetched, regardless of any limit. This
+ // should be safe from gdb side.
+ //
+ // Risk: If somebody provides a pretty printer for a collection,
+ // but forgets to implement the display_hint method, viewing
+ // the collection while it is uninitiliazed may cause gdb
+ // to never return.
+ //
+ // => The risk seams reasonable, so we require a limit only
+ // for collections.
+ boolean isDynamicButSafe = (displayHint == GdbDisplayHint.GDB_DISPLAY_HINT_STRING)
+ || (displayHint == GdbDisplayHint.GDB_DISPLAY_HINT_NONE);
+
+ return !isDynamic() || isDynamicButSafe;
+ }
public void setGdbName(String n) { gdbName = n; }
public void setCurrentFormat(String f) { format = f; }
-
+
+ /**
+ * @param fullExpression
+ * @param t
+ * @param num
+ *
+ * @deprecated Use
+ * {@link #setExpressionData(ExpressionInfo, String, int, boolean)}
+ * instead.
+ */
+ @Deprecated
public void setExpressionData(String fullExpression, String t, int num) {
- fullExp = fullExpression;
+ new ExpressionInfo(fullExpression, fullExpression);
+ }
+
+ /**
+ * @param info
+ * @param t
+ * @param num
+ * If the correspinding MI variable is dynamic, the number of
+ * children currently fetched by gdb.
+ * @param hasMore
+ * Whether their are more children to fetch.
+ *
+ * @since 4.0
+ */
+ public void setExpressionData(ExpressionInfo info, String t, int num, boolean hasMore) {
+ exprInfo = info;
type = t;
gdbType = fGDBTypeParser.parse(t);
numChildrenHint = num;
+ this.hasMore = hasMore;
}
public void setValue(String format, String val) { valueMap.put(format, val); }
@@ -337,12 +579,106 @@ public class MIVariableManager implements ICommandControl {
valueMap.put(IFormattedValues.DECIMAL_FORMAT, null);
}
- public void setChildren(ExpressionInfo[] c) { children = c; }
+ /**
+ * @param c
+ * The new children, or null in order to force fetching
+ * children anew.
+ */
+ public void setChildren(ExpressionInfo[] c) {
+ children = c;
+ if (children != null) {
+ numChildrenHint = children.length;
+ }
+
+ if (children != null) {
+ for (ExpressionInfo child : children) {
+ assert (child != null);
+ }
+ }
+ }
+
+ /**
+ * @param newChildren
+ *
+ * @since 4.0
+ */
+ public void addChildren(ExpressionInfo[] newChildren) {
+ if (children == null) {
+ children = new ExpressionInfo[newChildren.length];
+ System.arraycopy(newChildren, 0, children, 0, newChildren.length);
+ } else {
+ ExpressionInfo[] oldChildren = children;
+
+ children = new ExpressionInfo[children.length + newChildren.length];
+
+ System.arraycopy(oldChildren, 0, children, 0, oldChildren.length);
+ System.arraycopy(newChildren, 0, children, oldChildren.length, newChildren.length);
+ }
+
+ numChildrenHint = children.length;
+
+ for (ExpressionInfo child : children) {
+ assert (child != null);
+ }
+ }
+
+ /**
+ * @param newChildren
+ *
+ * @since 4.0
+ */
+ protected void addChildren(ExpressionInfo[][] newChildren) {
+ int requiredSize = 0;
+
+ for (ExpressionInfo[] subArray : newChildren) {
+ requiredSize += subArray.length;
+ }
+
+ ExpressionInfo[] plainChildren = new ExpressionInfo[requiredSize];
+
+ int i = 0;
+ for (ExpressionInfo[] subArray : newChildren) {
+ System.arraycopy(subArray, 0, plainChildren, i, subArray.length);
+ i += subArray.length;
+ }
+
+ addChildren(plainChildren);
+ }
+
+ /**
+ * @param newNumChildren
+ *
+ * @since 4.0
+ */
+ public void shrinkChildrenTo(int newNumChildren) {
+ if (children != null) {
+ ExpressionInfo[] oldChildren = children;
+ for (int i = oldChildren.length - 1; i >= newNumChildren; --i) {
+ String childFullExpression = children[i].getFullExpr();
+
+ VariableObjectId childId = new VariableObjectId();
+ childId.generateId(childFullExpression, getInternalId());
+ lruVariableList.remove(childId);
+ }
+
+
+ children = new ExpressionInfo[newNumChildren];
+ System.arraycopy(oldChildren, 0, children, 0, newNumChildren);
+ }
+
+ numChildrenHint = newNumChildren;
+ }
+
public void setParent(MIVariableObject p) {
parent = p;
- rootToUpdate = (p == null ? (MIRootVariableObject)this : p.getRootToUpdate());
+ if (p == null) {
+ rootToUpdate = (this instanceof MIRootVariableObject) ? (MIRootVariableObject) this
+ : null;
+ } else {
+ rootToUpdate = p.getRootToUpdate();
+ }
}
-
+
public void executeWhenNotUpdating(RequestMonitor rm) {
getRootToUpdate().executeWhenNotUpdating(rm);
}
@@ -362,6 +698,35 @@ public class MIVariableManager implements ICommandControl {
public boolean isOutOfScope() { return outOfScope; }
/**
+ * @param success
+ *
+ * @since 4.0
+ */
+ protected void creationCompleted(boolean success) {
+ // A creation completed we must be up-to-date, so we
+ // can tell any pending monitors that updates are done
+ if (success) {
+ currentState = STATE_READY;
+ while (updatesPending.size() > 0) {
+ DataRequestMonitor<Boolean> rm = updatesPending.poll();
+ // Nothing to be re-created
+ rm.setData(false);
+ rm.done();
+ }
+ } else {
+ currentState = STATE_CREATION_FAILED;
+
+ // Creation failed, inform anyone waiting.
+ while (updatesPending.size() > 0) {
+ RequestMonitor rm = updatesPending.poll();
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE,
+ "Unable to create variable object", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ }
+
+ /**
* This method updates the variable object.
* Updating a variable object is done by updating its root.
*/
@@ -373,7 +738,7 @@ public class MIVariableManager implements ICommandControl {
if (isOutOfScope()) {
rm.setData(false);
rm.done();
- } else if (currentState == STATE_UPDATING) {
+ } else if (currentState != STATE_READY) {
// If we were already updating, we just queue the request monitor
// until the on-going update finishes.
updatesPending.add(rm);
@@ -414,6 +779,169 @@ public class MIVariableManager implements ICommandControl {
}
/**
+ * Process an update on this variable object.
+ *
+ * @param update What has changed.
+ *
+ * @since 4.0
+ */
+ protected void processChange(final MIVarChange update, final RequestMonitor rm) {
+
+ MIVar[] newChildren = update.getNewChildren();
+
+ // children == null means fetchChildren will happen later, so
+ // don't try to create a sparsely filled children array here.
+ final boolean addNewChildren = (children != null);
+
+ final ExpressionInfo[] addedChildren = (addNewChildren && (newChildren != null)) ? new ExpressionInfo[newChildren.length]
+ : null;
+
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleCompleted() {
+
+ if (! isSuccess()) {
+ rm.setStatus(getStatus());
+ } else {
+ if (update.numChildrenChanged()) {
+ if (children != null) {
+ // Remove those children that don't exist any longer.
+ if (children.length > update.getNewNumChildren()) {
+ shrinkChildrenTo(update.getNewNumChildren());
+ }
+ } else {
+ // Just update the child count.
+ numChildrenHint = update.getNewNumChildren();
+ }
+
+ // Add the new children.
+ if ((addedChildren != null) && (addedChildren.length != 0)) {
+ addChildren(addedChildren);
+ }
+ }
+
+ assert((children == null) || (children.length == numChildrenHint));
+
+ hasMore = update.hasMore();
+
+ // If there was no -var-list-children yet for a varobj,
+ // the new children will not be reported by -var-update.
+ // Set the children to null such that the next time children
+ // are requested, they will be fetched.
+ if (hasMore() && (numChildrenHint == 0)) {
+ setChildren(null);
+ }
+
+ resetValues(update.getValue());
+ }
+ rm.done();
+ }
+ };
+
+ // Process all the child MIVariableObjects.
+ int pendingVariableCreationCount = 0;
+ if (newChildren != null && newChildren.length != 0) {
+ int i = update.getNewNumChildren() - newChildren.length;
+ int arrayPosition = 0;
+
+ for (final MIVar newChild : newChildren) {
+
+ // As long as http://sourceware.org/bugzilla/show_bug.cgi?id=10252
+ // is not fixed, it doesn't make sense to use
+ // -var-info-path-expression. New children can only
+ // be added during the update, if we are a child of a
+ // dynamic varobj, and in this case -var-info-path-expression
+ // won't work.
+ final String childFullExpression = buildChildExpression(
+ getExpression(), newChild.getExp());
+
+ // Now try to see if we already have this variable
+ // object in our Map
+ // Since our map names use the expression, and not the
+ // GDB given
+ // name, we must determine the correct map name from the
+ // varName
+ final VariableObjectId childId = new VariableObjectId();
+ childId.generateId(childFullExpression, getInternalId());
+ MIVariableObject childVar = lruVariableList.get(childId);
+
+ if (childVar != null) {
+ if ((childVar.currentState == STATE_CREATING)
+ || (childVar.currentState == STATE_NOT_CREATED)) {
+
+ // We must wait until the child MIVariableObject is fully created.
+ // This might succeed, or fail. If it succeeds, we can reuse it as
+ // a child, otherwise we create a new MIVariableObject for the
+ // varobj just provided by gdb.
+
+ ++pendingVariableCreationCount;
+
+ final int insertPosition = arrayPosition;
+ final MIVariableObject monitoredVar = childVar;
+ final int indexInParent = i;
+
+ // varobj is not fully created so add RequestMonitor to pending queue
+ childVar.updatesPending.add(new DataRequestMonitor<Boolean>(fSession.getExecutor(), countingRm) {
+
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ if (addNewChildren) {
+ addedChildren[insertPosition] = monitoredVar.exprInfo;
+ }
+ } else {
+ // Create a fresh MIVariableObject for this child, using
+ // the new varobj provided by gdb.
+ MIVariableObject newVar = createChild(childId, childFullExpression,
+ indexInParent, newChild);
+ if (addNewChildren) {
+ addedChildren[insertPosition] = newVar.exprInfo;
+ }
+ }
+
+ countingRm.done();
+ }
+
+ });
+
+ } else if (childVar.currentState == STATE_CREATION_FAILED) {
+ // There has been an attempt the create a MIRootVariableObject for a full
+ // expression representing a child of a dynamic varobj. Such an attempt
+ // always fails. But here we can now create it (see below).
+ childVar = null;
+ }
+ // Note that we must check the root to know if it is out-of-scope.
+ // We cannot check the child as it has not be updated and its
+ // outOfScope variable is not updated either.
+ else if (childVar.getRootToUpdate().isOutOfScope()) {
+ childVar.deleteInGdb();
+ childVar = null;
+ }
+ }
+
+ // Note: we don't need to check for fake children (public, protected, private) here.
+ // We enter this code only if the children are provided by a pretty printer and
+ // they don't return such children.
+
+ if (childVar == null) {
+ // Create a fresh MIVariableObject for this child, using
+ // the new varobj provided by -var-update.
+ childVar = createChild(childId, childFullExpression, i, newChild);
+ if (addNewChildren) {
+ addedChildren[arrayPosition] = childVar.exprInfo;
+ }
+ }
+
+ ++i;
+ ++arrayPosition;
+ }
+ }
+
+ countingRm.setDoneCount(pendingVariableCreationCount);
+ }
+
+ /**
* Variable objects need not be deleted unless they are root.
* This method is specialized in the MIRootVariableObject class.
*/
@@ -476,7 +1004,7 @@ public class MIVariableManager implements ICommandControl {
// If the variable is a complex structure, there is no need to ask the back-end for a value,
// we can give it the {...} ourselves
// Unless we are dealing with an array, in which case, we want to get the address of it
- if (isComplex()) {
+ if (isComplex() && ! isDynamic()) {
if (isArray()) {
// Figure out the address
IExpressionDMContext exprCxt = DMContexts.getAncestorOfType(dmc, IExpressionDMContext.class);
@@ -613,29 +1141,108 @@ public class MIVariableManager implements ICommandControl {
}
}
- /**
- * This method returns the list of children of the variable object passed as a parameter.
+ /**
+ * This method returns the list of children of the variable object
+ * passed as a parameter.
+ *
+ * @param exprDmc
+ *
+ * @param clientNumChildrenLimit
+ * If the current limit for the given expression is smaller,
+ * this limit will be applied.
+ * @param rm
+ * The data request monitor that will hold the children
+ * returned
+ */
+ private void getChildren(final MIExpressionDMC exprDmc,
+ final int clientNumChildrenLimit, final DataRequestMonitor<ChildrenInfo> rm) {
+
+ if (fetchingChildren) {
+ // Only one request monitor can fetch children at a time.
+ fetchChildrenPending.add(new DataRequestMonitor<ChildrenInfo>(fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleSuccess() {
+ ChildrenInfo info = getData();
+ int numChildren = info.getChildren().length;
+ if (! info.hasMore() || numChildren >= clientNumChildrenLimit) {
+ // No need to fetch further children.
+ rm.setData(getData());
+ rm.done();
+ } else {
+ // Need to retry.
+ getChildren(exprDmc, clientNumChildrenLimit, rm);
+ }
+ }
+
+ });
+ } else {
+
+ fetchingChildren = true;
+
+ fetchChildren(exprDmc, clientNumChildrenLimit, new DataRequestMonitor<ChildrenInfo>(fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleCompleted() {
+ fetchingChildren = false;
+
+ if (isSuccess()) {
+ rm.setData(getData());
+ rm.done();
+
+ while (fetchChildrenPending.size() > 0) {
+ DataRequestMonitor<ChildrenInfo> pendingRm = fetchChildrenPending.poll();
+ pendingRm.setData(getData());
+ pendingRm.done();
+ }
+ } else {
+ rm.setStatus(getStatus());
+ rm.done();
+
+ while (fetchChildrenPending.size() > 0) {
+ DataRequestMonitor<ChildrenInfo> pendingRm = fetchChildrenPending.poll();
+ pendingRm.setStatus(getStatus());
+ pendingRm.done();
+ }
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Fetch the out-standing children.
+ *
+ * @param exprDmc
*
+ * @param clientNumChildrenLimit
+ * If the current limit for the given expression is smaller,
+ * this limit will be applied.
* @param rm
- * The data request monitor that will hold the children returned
+ * The data request monitor that will hold the children
+ * returned
*/
- private void getChildren(final MIExpressionDMC exprDmc, final DataRequestMonitor<ExpressionInfo[]> rm) {
+ private void fetchChildren(final MIExpressionDMC exprDmc,
+ int clientNumChildrenLimit, final DataRequestMonitor<ChildrenInfo> rm) {
+
+ final int newNumChildrenLimit = clientNumChildrenLimit != IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED ?
+ clientNumChildrenLimit : 1;
+
+ boolean addChildren = requiresAdditionalChildren(newNumChildrenLimit);
// If we already know the children, no need to go to the back-end
ExpressionInfo[] childrenArray = getChildren();
- if (childrenArray != null) {
- rm.setData(childrenArray);
+ if (childrenArray != null && ! addChildren) {
+ rm.setData(new ChildrenInfo(childrenArray, hasMore));
rm.done();
return;
}
// If the variable does not have children, we can return an empty list right away
- // The numChildrenHint value is trustworthy when wanting to know if there are children
- // at all.
- if (getNumChildrenHint() == 0) {
+ if (! hasChildren()) {
// First store the empty list, for the next time
setChildren(new ExpressionInfo[0]);
- rm.setData(getChildren());
+ rm.setData(new ChildrenInfo(getChildren(), hasMore));
rm.done();
return;
}
@@ -643,9 +1250,8 @@ public class MIVariableManager implements ICommandControl {
// For arrays (which could be very large), we create the children ourselves. This is
// to avoid creating an enormous amount of children variable objects that the view may
// never need. Using -var-list-children will create a variable object for every child
- // immediately, that is why won't don't want to use it for arrays.
+ // immediately, that is why we don't want to use it for arrays.
if (isArray()) {
- // We can trust the numChildrenHint value for arrays.
ExpressionInfo[] childrenOfArray = new ExpressionInfo[getNumChildrenHint()];
String exprName = exprDmc.getExpression();
@@ -661,12 +1267,13 @@ public class MIVariableManager implements ICommandControl {
String fullExpr = exprName + "[" + i + "]";//$NON-NLS-1$//$NON-NLS-2$
String relExpr = exprDmc.getRelativeExpression() + "[" + (castingIndex + i) + "]";//$NON-NLS-1$//$NON-NLS-2$
- childrenOfArray[i] = new ExpressionInfo(fullExpr, relExpr);
+ childrenOfArray[i] = new ExpressionInfo(fullExpr, relExpr, false, exprInfo, i);
}
// First store these children, for the next time
setChildren(childrenOfArray);
- rm.setData(getChildren());
+ hasMore = false;
+ rm.setData(new ChildrenInfo(getChildren(), hasMore));
rm.done();
return;
}
@@ -675,26 +1282,58 @@ public class MIVariableManager implements ICommandControl {
// at any time, as long as the object is created, which we know it is, since we can only
// be called here with a fully created object.
// Also no need to lock the object, since getting the children won't affect other operations
+
+ final int from = (addChildren && (children != null)) ? getNumChildrenHint() : 0;
+ final int to = Math.max(newNumChildrenLimit, exprInfo.getChildCountLimit());
+
+ ICommand<MIVarListChildrenInfo> varListChildren = isSafeToAskForAllChildren() ?
+ fCommandFactory.createMIVarListChildren(getRootToUpdate().getControlDMContext(), getGdbName())
+ :fCommandFactory.createMIVarListChildren(getRootToUpdate().getControlDMContext(), getGdbName(), from, to);
+
fCommandControl.queueCommand(
- fCommandFactory.createMIVarListChildren(getRootToUpdate().getControlDMContext(), getGdbName()),
+ varListChildren,
new DataRequestMonitor<MIVarListChildrenInfo>(fSession.getExecutor(), rm) {
@Override
protected void handleSuccess() {
MIVar[] children = getData().getMIVars();
- final List<ExpressionInfo> realChildren = new ArrayList<ExpressionInfo>();
+ final boolean localHasMore = getData().hasMore();
+
+ // The elements of this array normally are an ExpressionInfo, unless it corresponds to
+ // a fake child (public, protected, private). In this case it is an ExpressionInfo[]
+ // representing the children of the fake child.
+ // This in done in order to preserve the order (the index-in-parent information),
+ // when replacing a fake child by its real children.
+ final ExpressionInfo[][] realChildren = new ExpressionInfo[children.length][];
final CountingRequestMonitor countingRm = new CountingRequestMonitor(fSession.getExecutor(), rm) {
@Override
protected void handleSuccess() {
// Store the children in our variable object cache
- setChildren(realChildren.toArray(new ExpressionInfo[realChildren.size()]));
- rm.setData(getChildren());
- rm.done();
+ addChildren(realChildren);
+ hasMore = localHasMore;
+ rm.setData(new ChildrenInfo(getChildren(), hasMore));
+
+ int updateLimit = updateLimit(to);
+
+ if (! isSafeToAskForAllChildren()) {
+ // Make sure the gdb will not hang, if later
+ // the varobj is updated, but the underlying
+ // data is still uninitialized.
+ fCommandControl.queueCommand(
+ fCommandFactory.createMIVarSetUpdateRange(getRootToUpdate().getControlDMContext(),
+ getGdbName(), 0, updateLimit), new DataRequestMonitor<MIInfo>(fSession.getExecutor(), rm));
+ } else {
+ rm.done();
+ }
}
};
int numSubRequests = 0;
- for (final MIVar child : children) {
+ for (int i = 0; i < children.length; ++i) {
+ final MIVar child = children[i];
+ final int indexInParent = from + i;
+ final int arrayPosition = i;
+
// These children get created automatically as variable objects in GDB, so we should
// add them to the LRU.
// Note that if this variable object already exists, we can be in three scenarios:
@@ -717,68 +1356,84 @@ public class MIVariableManager implements ICommandControl {
new DataRequestMonitor<String>(fSession.getExecutor(), countingRm) {
@Override
protected void handleSuccess() {
- String childFullExpression = getData();
-
// For children that do not map to a real expression (such as f.public)
// GDB returns an empty string. In this case, we can use another unique
// name, such as the variable name
- boolean fakeChild = false;
- if (childFullExpression.length() == 0) {
- fakeChild = true;
- childFullExpression = child.getVarName();
- }
-
+ final boolean fakeChild = (getData().length() == 0);
+ final String childFullExpression = fakeChild ? child.getVarName() : getData();
+
// Now try to see if we already have this variable object in our Map
// Since our map names use the expression, and not the GDB given
// name, we must determine the correct map name from the varName
- VariableObjectId childId = new VariableObjectId();
+ final VariableObjectId childId = new VariableObjectId();
childId.generateId(childFullExpression, getInternalId());
MIVariableObject childVar = lruVariableList.get(childId);
- // Note that we must check the root to know if it is out-of-scope.
- // We cannot check the child as it has not be updated and its
- // outOfScope variable is not updated either.
- if (childVar != null && childVar.getRootToUpdate().isOutOfScope()) {
- childVar.deleteInGdb();
- childVar = null;
- }
+ if (childVar != null) {
+
+ if ((childVar.currentState == STATE_CREATING)
+ || (childVar.currentState == STATE_NOT_CREATED)) {
+
+ // We must wait until the child MIVariableObject is fully created.
+ // This might succeed, or fail. If it succeeds, we can reuse it as
+ // a child, otherwise we create a new MIVariableObject for the
+ // varobj just provided by gdb.
+
+ final MIVariableObject monitoredVar = childVar;
+
+ // childVar is not fully created so add a RequestMonitor to the queue
+ childVar.updatesPending.add(new DataRequestMonitor<Boolean>(fSession.getExecutor(), countingRm) {
+
+ @Override
+ protected void handleCompleted() {
+ MIVariableObject var = monitoredVar;
+
+ if (! isSuccess()) {
+
+ // Create a fresh MIVariableObject for this child, using
+ // the new varobj provided by gdb.
+ var = createChild(childId, childFullExpression, indexInParent, child);
+ }
+
+ if (fakeChild) {
+
+ addRealChildrenOfFake(var, exprDmc, realChildren,
+ arrayPosition, countingRm);
+ } else {
+ // This is a real child
+ realChildren[arrayPosition] = new ExpressionInfo[] { var.exprInfo };
+ countingRm.done();
+ }
+ }
+ });
+
+ } else if (childVar.currentState == STATE_CREATION_FAILED) {
+ // There has been an attempt the create a MIRootVariableObject for a full
+ // expression representing a child of a dynamic varobj. Such an attempt always
+ // fails. But here we can now create it (see below).
+ childVar = null;
+ }
+ // Note that we must check the root to know if it is out-of-scope.
+ // We cannot check the child as it has not be updated and its
+ // outOfScope variable is not updated either.
+ else if (childVar.getRootToUpdate().isOutOfScope()) {
+ childVar.deleteInGdb();
+ childVar = null;
+ }
+ }
if (childVar == null) {
- childVar = createVariableObject(childId, MIVariableObject.this);
- childVar.setGdbName(child.getVarName());
- childVar.setExpressionData(
- childFullExpression,
- child.getType(),
- child.getNumChild());
-
- // This will replace any existing entry
- lruVariableList.put(childId, childVar);
-
- // Is this new child a modifiable descendant of the root?
- if (childVar.isModifiable()) {
- getRootToUpdate().addModifiableDescendant(child.getVarName(), childVar);
- }
- }
-
- if (fakeChild) {
- // This is just a qualifier level of C++, and we must
- // get the children of this child to get the real children
- childVar.getChildren(
- exprDmc,
- new DataRequestMonitor<ExpressionInfo[]>(fSession.getExecutor(), countingRm) {
- @Override
- protected void handleSuccess() {
- ExpressionInfo[] vars = getData();
- for (ExpressionInfo realChild : vars) {
- realChildren.add(realChild);
- }
- countingRm.done();
- }
- });
- } else {
- // This is a real child
- realChildren.add(new ExpressionInfo(childFullExpression, child.getExp()));
- countingRm.done();
+ childVar = createChild(childId, childFullExpression, indexInParent, child);
+
+ if (fakeChild) {
+
+ addRealChildrenOfFake(childVar, exprDmc, realChildren,
+ arrayPosition, countingRm);
+ } else {
+ // This is a real child
+ realChildren[arrayPosition] = new ExpressionInfo[] { childVar.exprInfo };
+ countingRm.done();
+ }
}
}
};
@@ -789,6 +1444,12 @@ public class MIVariableManager implements ICommandControl {
// to call -var-info-path-expression for real, but just pretend we did.
childPathRm.setData(""); //$NON-NLS-1$
childPathRm.done();
+ } else if (isDynamic() || exprInfo.hasDynamicAncestor()) {
+ // Equivalent to (which can't be implemented): child.hasDynamicAncestor
+ // The new child has a dynamic ancestor. Such children don't support
+ // var-info-path-expression. Build the expression ourselves.
+ childPathRm.setData(buildChildExpression(exprDmc.getExpression(), child.getExp()));
+ childPathRm.done();
} else {
// To build the child id, we need the fully qualified expression which we
// can get from -var-info-path-expression starting from GDB 6.7
@@ -817,6 +1478,111 @@ public class MIVariableManager implements ICommandControl {
}
/**
+ * Create a child variable of this MIVariableObject and initialize
+ * it from the given MIVar data.
+ *
+ * @param childId
+ * @param childFullExpression
+ * @param indexInParent
+ * @param childData
+ *
+ * @return The new child.
+ *
+ * @since 4.0
+ */
+ protected MIVariableObject createChild(final VariableObjectId childId,
+ final String childFullExpression, final int indexInParent,
+ final MIVar childData) {
+
+ MIVariableObject var = createVariableObject(childId, this);
+ ExpressionInfo childInfo = new ExpressionInfo(childFullExpression,
+ childData.getExp(), childData.isDynamic(), exprInfo,
+ indexInParent);
+
+ var.initFrom(childData, childInfo);
+ return var;
+ }
+
+ /**
+ * @param clientLimit
+ * @return True, if the client specified limit requires to check for
+ * further children.
+ *
+ * @since 4.0
+ */
+ protected boolean requiresAdditionalChildren(int clientLimit) {
+ return !isSafeToAskForAllChildren()
+ && (exprInfo.getChildCountLimit() < calculateNewLimit(clientLimit));
+ }
+
+ /**
+ * @param newLimit
+ * The new limit on the number of children being asked for or
+ * being updated.
+ *
+ * @return The new limit.
+ * @since 4.0
+ */
+ protected int updateLimit(int newLimit) {
+ exprInfo.setChildCountLimit(calculateNewLimit(newLimit));
+ return exprInfo.getChildCountLimit();
+ }
+
+ private int calculateNewLimit(int clientLimit) {
+ int limit = exprInfo.getChildCountLimit();
+
+ if (!isSafeToAskForAllChildren() && clientLimit != IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED) {
+ if (limit == IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED) {
+ return clientLimit;
+ } else if (limit < clientLimit) {
+ return clientLimit;
+ }
+ }
+
+ return limit;
+ }
+
+ /**
+ * Obtain the children of the given fake child (public, protected, or
+ * private) and insert them into a list of children at a given position.
+ *
+ * @param fakeChild
+ * @param frameCtxProvider
+ * @param realChildren
+ * @param position
+ * @param rm The request monitor on which to call done upon completion.
+ */
+ private void addRealChildrenOfFake(MIVariableObject fakeChild,
+ IExpressionDMContext frameCtxProvider,
+ final ExpressionInfo[][] realChildren, final int position,
+ final CountingRequestMonitor rm) {
+
+ MIExpressionDMC fakeExprCtx = createExpressionCtx(frameCtxProvider,
+ fakeChild.exprInfo);
+
+ // This is just a qualifier level of C++, and we must get the
+ // children of this child to get the real children
+ fakeChild.getChildren(fakeExprCtx,
+ IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED,
+ new DataRequestMonitor<ChildrenInfo>(
+ fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ realChildren[position] = getData()
+ .getChildren();
+
+ // Fake nodes can never be dynamic varobjs, and because
+ // of this, hasMore is always false.
+ assert (!getData().hasMore());
+ }
+ rm.done();
+ }
+ });
+ }
+
+ /**
* This method builds a child expression based on its parent's expression.
* It is a fallback solution for when GDB doesn't support the var-info-path-expression.
*
@@ -839,28 +1605,40 @@ public class MIVariableManager implements ICommandControl {
// and don't call this method for them
}
- /**
- * This method returns the count of children of the variable object passed as a parameter.
+ /**
+ * This method returns the count of children of the variable object
+ * passed as a parameter.
*
+ * @param exprDmc
+ *
+ * @param numChildrenLimit
+ * No need to check for more than this number of children.
+ * However, it is legal to return a higher count if
+ * we already new from earlier call that there are more
+ * children.
+ *
* @param rm
- * The data request monitor that will hold the count of children returned
+ * The data request monitor that will hold the count of
+ * children returned
*/
- private void getChildrenCount(MIExpressionDMC exprDmc, final DataRequestMonitor<Integer> rm) {
+ private void getChildrenCount(MIExpressionDMC exprDmc, final int numChildrenLimit,
+ final DataRequestMonitor<ChildrenCountInfo> rm) {
if (isNumChildrenHintTrustworthy()){
- rm.setData(getNumChildrenHint());
+ rm.setData(new ChildrenCountInfo(getNumChildrenHint(), hasMore()));
rm.done();
return;
}
- getChildren(
- exprDmc,
- new DataRequestMonitor<ExpressionInfo[]>(fSession.getExecutor(), rm) {
- @Override
- protected void handleSuccess() {
- rm.setData(getData().length);
- rm.done();
- }
- });
+ getChildren(exprDmc, numChildrenLimit,
+ new DataRequestMonitor<ChildrenInfo>(fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleSuccess() {
+ rm.setData(new ChildrenCountInfo(getData()
+ .getChildren().length, getData().hasMore()));
+ rm.done();
+ }
+ });
}
@@ -966,10 +1744,91 @@ public class MIVariableManager implements ICommandControl {
return str.equals("private") || str.equals("public") || str.equals("protected"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
+ /**
+ * @return If true, this variable object can be reported as changed in
+ * a -var-update MI command.
+ */
public boolean isModifiable() {
- if (!isComplex()) return true;
+ if (!isComplex() || isDynamic()) return true;
return false;
}
+
+ /**
+ * @param exprCtx
+ * @param rm
+ *
+ * @since 4.0
+ */
+ public void create(final IExpressionDMContext exprCtx,
+ final RequestMonitor rm) {
+
+ if (currentState == STATE_NOT_CREATED) {
+
+ currentState = STATE_CREATING;
+
+ final MIExpressionDMC miExprCtx = (MIExpressionDMC) exprCtx;
+ final int indexInParent = miExprCtx.getExpressionInfo().getIndexInParentExpression();
+
+ fCommandControl.queueCommand(fCommandFactory.createMIVarListChildren(getParent().getRootToUpdate().getControlDMContext(),
+ getParent().getGdbName(), indexInParent, indexInParent + 1),
+ new DataRequestMonitor<MIVarListChildrenInfo>(fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleSuccess() {
+ if (getData().getMIVars().length == 1) {
+ MIVar miVar = getData().getMIVars()[0];
+
+ ExpressionInfo localExprInfo = miExprCtx.getExpressionInfo();
+
+ localExprInfo.setDynamic(miVar.isDynamic());
+
+ initFrom(miVar, localExprInfo);
+
+ if (exprInfo.isDynamic()
+ && (exprInfo.getChildCountLimit() != IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED)) {
+ // Restore the original update range.
+ fCommandControl.queueCommand(fCommandFactory.createMIVarSetUpdateRange(
+ getRootToUpdate().getControlDMContext(),
+ getGdbName(), 0, exprInfo.getChildCountLimit()),
+ new DataRequestMonitor<MIInfo>(fSession.getExecutor(), rm));
+ } else {
+ rm.done();
+ }
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+ "Unexpected return on -var-list-children", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ });
+ } else {
+ assert false;
+ }
+ }
+
+ private void initFrom(MIVar miVar, ExpressionInfo newExprInfo) {
+ // Possible Optimization in GDB: In -var-list-children, the has_more
+ // field is missing for the children. As a workaround, we assume that
+ // if numChild is 0 and has_more is omitted, we have more children.
+ boolean newHasMore = miVar.hasMore()
+ || (miVar.isDynamic() && (miVar.getNumChild() == 0));
+
+ setGdbName(miVar.getVarName());
+ setDisplayHint(miVar.getDisplayHint());
+ setExpressionData(
+ newExprInfo,
+ miVar.getType(),
+ miVar.getNumChild(),
+ newHasMore);
+
+ // This will replace any existing entry
+ lruVariableList.put(getInternalId(), this);
+
+ // Is this new child a modifiable descendant of the root?
+ if (isModifiable()) {
+ getRootToUpdate().addModifiableDescendant(miVar.getVarName(), this);
+ }
+ }
}
/**
@@ -980,16 +1839,22 @@ public class MIVariableManager implements ICommandControl {
protected MIVariableObject createVariableObject(VariableObjectId id, MIVariableObject parentObj) {
return new MIVariableObject(id, parentObj);
}
-
+
+ /**
+ * Method to allow to override the MIVariableObject creation
+ *
+ * @since 4.0
+ */
+ protected MIVariableObject createVariableObject(VariableObjectId id,
+ MIVariableObject parentObj, boolean needsCreation) {
+ return new MIVariableObject(id, parentObj, needsCreation);
+ }
+
/**
* @since 3.0
*/
public class MIRootVariableObject extends MIVariableObject {
- // Only root variables go through the GDB creation process
- protected static final int STATE_NOT_CREATED = 10;
- protected static final int STATE_CREATING = 11;
-
// The control context within which this variable object was created
// It only needs to be stored in the Root VarObj since any children
// will have the same control context
@@ -997,8 +1862,11 @@ public class MIVariableManager implements ICommandControl {
private boolean fOutOfDate = false;
- // Modifiable descendants are any variable object that is a descendant or itself for
- // which the value can change.
+ /**
+ * A modifiable descendant is any variable object that is a descendant and
+ * for which the value (leaf variable objects and dynamic variable objects)
+ * or number of children (dynamic variable objects) can change.
+ */
private Map<String, MIVariableObject> modifiableDescendants;
public MIRootVariableObject(VariableObjectId id) {
@@ -1020,14 +1888,29 @@ public class MIVariableManager implements ICommandControl {
modifiableDescendants.put(gdbName, descendant);
}
- public void processChanges(MIVarChange[] updates) {
+ /**
+ * @since 4.0
+ */
+ public void processChanges(MIVarChange[] updates, RequestMonitor rm) {
+ CountingRequestMonitor countingRm = new CountingRequestMonitor(fSession.getExecutor(), rm);
+ countingRm.setDoneCount(updates.length);
+
for (MIVarChange update : updates) {
MIVariableObject descendant = modifiableDescendants.get(update.getVarName());
+
// Descendant should never be null, but just to be safe
- if (descendant != null) descendant.resetValues(update.getValue());
+ if (descendant != null) {
+ descendant.processChange(update, countingRm);
+ } else {
+ // This can for instance happen if a child MIVariableObject is deleted
+ // from the cache. The corresponding varobj in gdb does still exist,
+ // and if it is changed, gdb reports it as changed in -var-update.
+ countingRm.done();
+ }
}
}
+ @Override
public void create(final IExpressionDMContext exprCtx,
final RequestMonitor rm) {
@@ -1043,10 +1926,22 @@ public class MIVariableManager implements ICommandControl {
protected void handleCompleted() {
if (isSuccess()) {
setGdbName(getData().getName());
+ setDisplayHint(getData().getDisplayHint());
+
+ MIExpressionDMC miExprCtx = (MIExpressionDMC) exprCtx;
+ ExpressionInfo localExprInfo = miExprCtx
+ .getExpressionInfo();
+
+ localExprInfo.setDynamic(getData()
+ .isDynamic());
+ localExprInfo.setParent(null);
+ localExprInfo.setIndexInParent(-1);
+
setExpressionData(
- exprCtx.getExpression(),
- getData().getType(),
- getData().getNumChildren());
+ localExprInfo,
+ getData().getType(),
+ getData().getNumChildren(),
+ getData().hasMore());
// Store the value returned at create (available in GDB 6.7)
// Don't store if it is an array, since we want to show
@@ -1059,11 +1954,22 @@ public class MIVariableManager implements ICommandControl {
if (isModifiable()) {
addModifiableDescendant(getData().getName(), MIRootVariableObject.this);
}
+
+ if (localExprInfo.isDynamic()
+ && (localExprInfo.getChildCountLimit() != IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED)) {
+
+ // Restore the original update range.
+ fCommandControl.queueCommand(fCommandFactory.createMIVarSetUpdateRange(
+ getRootToUpdate().getControlDMContext(),getGdbName(),
+ 0,localExprInfo.getChildCountLimit()),
+ new DataRequestMonitor<MIInfo>(fSession.getExecutor(), rm));
+ } else {
+ rm.done();
+ }
} else {
rm.setStatus(getStatus());
- }
-
- rm.done();
+ rm.done();
+ }
}
});
} else {
@@ -1071,30 +1977,6 @@ public class MIVariableManager implements ICommandControl {
}
}
- private void creationCompleted(boolean success) {
- // A creation completed we must be up-to-date, so we
- // can tell any pending monitors that updates are done
- if (success) {
- currentState = STATE_READY;
- while (updatesPending.size() > 0) {
- DataRequestMonitor<Boolean> rm = updatesPending.poll();
- // Nothing to be re-created
- rm.setData(false);
- rm.done();
- }
- } else {
- currentState = STATE_NOT_CREATED;
-
- // Creation failed, inform anyone waiting.
- while (updatesPending.size() > 0) {
- RequestMonitor rm = updatesPending.poll();
- rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE,
- "Unable to create variable object", null)); //$NON-NLS-1$
- rm.done();
- }
- }
- }
-
@Override
public void update(final DataRequestMonitor<Boolean> rm) {
@@ -1136,7 +2018,32 @@ public class MIVariableManager implements ICommandControl {
if (isSuccess()) {
setOutOfDate(false);
+
+ CountingRequestMonitor countingRm = new CountingRequestMonitor(fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleCompleted() {
+ if (!isSuccess()) {
+ rm.setStatus(getStatus());
+ }
+ rm.done();
+
+ while (updatesPending.size() > 0) {
+ DataRequestMonitor<Boolean> pendingRm = updatesPending.poll();
+ if (isSuccess()) {
+ pendingRm.setData(false);
+ } else {
+ rm.setStatus(getStatus());
+ }
+
+ pendingRm.done();
+ }
+ }
+ };
+
+ int rmCount = 0;
+
MIVarChange[] changes = getData().getMIVarChanges();
if (changes.length > 0 && changes[0].isInScope() == false) {
// Object is out-of-scope
@@ -1152,10 +2059,10 @@ public class MIVariableManager implements ICommandControl {
lruVariableList.remove(getInternalId());
rm.setData(true);
- rm.done();
} else {
// The root object is now up-to-date, we must parse the changes, if any.
- processChanges(changes);
+ ++rmCount;
+ processChanges(changes, new RequestMonitor(fSession.getExecutor(), countingRm));
// We only mark this root as updated in our list if it is in-scope.
// For out-of-scope object, we don't ever need to re-update them so
@@ -1163,14 +2070,10 @@ public class MIVariableManager implements ICommandControl {
rootVariableUpdated(MIRootVariableObject.this);
rm.setData(false);
- rm.done();
}
- while (updatesPending.size() > 0) {
- DataRequestMonitor<Boolean> pendingRm = updatesPending.poll();
- pendingRm.setData(false);
- pendingRm.done();
- }
+ countingRm.setDoneCount(rmCount);
+
} else {
// We were not able to update for some reason
rm.setData(false);
@@ -1195,7 +2098,7 @@ public class MIVariableManager implements ICommandControl {
* to be deleted automatically when their root is deleted.
*/
@Override
- public void deleteInGdb() {
+ public void deleteInGdb() {
if (getGdbName() != null) {
fCommandControl.queueCommand(
fCommandFactory.createMIVarDelete(getRootToUpdate().getControlDMContext(), getGdbName()),
@@ -1210,6 +2113,8 @@ public class MIVariableManager implements ICommandControl {
} else {
// Variable was never created or was already deleted, no need to do anything.
}
+
+ super.deleteInGdb();
}
}
@@ -1385,7 +2290,9 @@ public class MIVariableManager implements ICommandControl {
@Override
public MIVariableObject remove(Object key) {
MIVariableObject varObj = super.remove(key);
- varObj.deleteInGdb();
+ if (varObj != null) {
+ varObj.deleteInGdb();
+ }
return varObj;
}
}
@@ -1542,6 +2449,16 @@ public class MIVariableManager implements ICommandControl {
}
} else {
// The variable object is up-to-date and valid
+
+ MIExpressionDMC miExprCtx = (MIExpressionDMC) exprCtx;
+ ExpressionInfo ctxExprInfo = miExprCtx.getExpressionInfo();
+ ExpressionInfo varExprInfo = varObj.getExpressionInfo();
+ if (ctxExprInfo != varExprInfo) {
+ // exprCtrx could just be created via IExpressions.createExpression,
+ // and thus the parent-child relationship is not yet set.
+ miExprCtx.setExpressionInfo(varExprInfo);
+ }
+
rm.setData(varObj);
rm.done();
}
@@ -1559,6 +2476,72 @@ public class MIVariableManager implements ICommandControl {
final IExpressionDMContext exprCtx,
final DataRequestMonitor<MIVariableObject> rm) {
+ // If we have a dynamic variable object as ancestor, we cannot use
+ // -var-create, so we must create ourselves creating the root, and
+ // then use -var-list-children for each further ancestor.
+ final MIExpressionDMC miExprCtx =(MIExpressionDMC) exprCtx;
+ final ExpressionInfo parentInfo = miExprCtx.getExpressionInfo().getParent();
+
+ if ((parentInfo != null) && miExprCtx.getExpressionInfo().hasDynamicAncestor()) {
+
+ // Need to set parent when it is known.
+ final MIVariableObject newVarObj = createVariableObject(id, null, true);
+
+ // We must put this object in our map right away, in case it is
+ // requested again, before it completes its creation.
+ // Note that this will replace any old entry with the same id.
+ lruVariableList.put(id, newVarObj);
+
+ MIExpressionDMC parentExprCtx = createExpressionCtx(exprCtx,
+ parentInfo);
+
+ getVariable(parentExprCtx,
+ new DataRequestMonitor<MIVariableObject>(
+ fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleCompleted() {
+
+ if (isSuccess()) {
+ final MIVariableObject parentObj = getData();
+ newVarObj.setParent(parentObj);
+
+ newVarObj.create(miExprCtx, new RequestMonitor(fSession.getExecutor(), rm) {
+
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ rm.setData(newVarObj);
+ newVarObj.creationCompleted(true);
+ } else {
+ // Object was not created, remove it from our list
+ lruVariableList.remove(id);
+ // We avoid this race condition by sending the notifications _after_ removing
+ // the object from the LRU, to avoid any new requests being queue.
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=231655
+ newVarObj.creationCompleted(false);
+ rm.setStatus(getStatus());
+ }
+ rm.done();
+ }
+ });
+ } else {
+ // Object was not created, remove it from our list
+ lruVariableList.remove(id);
+ // We avoid this race condition by sending the notifications _after_ removing
+ // the object from the LRU, to avoid any new requests being queue.
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=231655
+ newVarObj.creationCompleted(false);
+
+ rm.setStatus(getStatus());
+ rm.done();
+ }
+ }
+ });
+
+ return;
+ }
+
// Variable objects that are created directly like this, are considered ROOT variable objects
// in comparison to variable objects that are children of other variable objects.
final MIRootVariableObject newVarObj = createRootVariableObject(id);
@@ -1602,10 +2585,22 @@ public class MIVariableManager implements ICommandControl {
});
}
+ private MIExpressionDMC createExpressionCtx(
+ final IExpressionDMContext frameCtxProvider,
+ final ExpressionInfo exprInfo) {
+
+ IFrameDMContext frameCtx = DMContexts.getAncestorOfType(frameCtxProvider, IFrameDMContext.class);
+
+ MIExpressionDMC exprCtx = new MIExpressionDMC(
+ frameCtxProvider.getSessionId(), exprInfo, frameCtx);
+
+ return exprCtx;
+ }
+
/**
* This method requests the back-end to change the value of an expression.
*
- * @param expressionContext
+ * @param ctx
* The context of the expression we want to change
* @param expressionValue
* The new value of the expression
@@ -1652,18 +2647,52 @@ public class MIVariableManager implements ICommandControl {
new DataRequestMonitor<MIVariableObject>(fSession.getExecutor(), drm) {
@Override
protected void handleSuccess() {
- drm.setData(
- new ExprMetaGetVarInfo(
- exprCtx.getRelativeExpression(),
- // We only provide the hint here. It will be used for hasChildren()
- // To obtain the correct number of children, the user should use
- // IExpressions#getSubExpressionCount()
- getData().getNumChildrenHint(),
- getData().getType(),
- getData().getGDBType(),
- !getData().isComplex()));
- drm.done();
- processCommandDone(token, drm.getData());
+ final MIVariableObject varObj = getData();
+
+ if (varObj.isDynamic() && (varObj.getNumChildrenHint() == 0) && varObj.hasMore()) {
+ // Bug/feature in gdb? MI sometimes reports 0 number of children, and hasMore=1.
+ // This however, is not a safe indicator that there are children,
+ // unless there has been a -var-list-children before.
+ // The following call will
+ // 1) try to fetch at least one child, because isNumChildrenHintTrustworthy()
+ // returns false for this combination
+ // 2) result in the desired -var-list-children, unless it has happened already
+ // such that the number of children can at least be used to reliably
+ // tell whether there are children or not.
+ varObj.getChildrenCount(
+ exprCtx, 1,
+ new DataRequestMonitor<ChildrenCountInfo>(fSession.getExecutor(), drm) {
+ @Override
+ protected void handleSuccess() {
+ drm.setData(
+ new ExprMetaGetVarInfo(
+ exprCtx.getRelativeExpression(),
+ varObj.isSafeToAskForAllChildren(),
+ getData().getChildrenCount(),
+ varObj.getType(),
+ varObj.getGDBType(),
+ !varObj.isComplex(),
+ varObj.getDisplayHint().isCollectionHint()));
+ drm.done();
+ processCommandDone(token, drm.getData());
+ }
+ });
+ } else {
+ drm.setData(
+ new ExprMetaGetVarInfo(
+ exprCtx.getRelativeExpression(),
+ varObj.isSafeToAskForAllChildren(),
+ // We only provide the hint here. It will be used for hasChildren()
+ // To obtain the correct number of children, the user should use
+ // IExpressions#getSubExpressionCount()
+ varObj.getNumChildrenHint(),
+ varObj.getType(),
+ varObj.getGDBType(),
+ !varObj.isComplex(),
+ varObj.getDisplayHint().isCollectionHint()));
+ drm.done();
+ processCommandDone(token, drm.getData());
+ }
}
});
} else if (command instanceof ExprMetaGetAttributes) {
@@ -1724,14 +2753,14 @@ public class MIVariableManager implements ICommandControl {
new DataRequestMonitor<MIVariableObject>(fSession.getExecutor(), drm) {
@Override
protected void handleSuccess() {
- getData().getChildren(
- exprCtx,
- new DataRequestMonitor<ExpressionInfo[]>(fSession.getExecutor(), drm) {
+ getData().getChildren(exprCtx, ((ExprMetaGetChildren)command).getNumChildLimit(),
+ new DataRequestMonitor<ChildrenInfo>(fSession.getExecutor(), drm) {
@Override
protected void handleSuccess() {
- drm.setData(new ExprMetaGetChildrenInfo(getData()));
+ drm.setData(new ExprMetaGetChildrenInfo(
+ getData().getChildren()));
drm.done();
- processCommandDone(token, drm.getData());
+ processCommandDone(token, drm.getData());
}
});
}
@@ -1741,18 +2770,20 @@ public class MIVariableManager implements ICommandControl {
@SuppressWarnings("unchecked")
final DataRequestMonitor<ExprMetaGetChildCountInfo> drm = (DataRequestMonitor<ExprMetaGetChildCountInfo>)rm;
final MIExpressionDMC exprCtx = (MIExpressionDMC)(command.getContext());
-
+
getVariable(
exprCtx,
new DataRequestMonitor<MIVariableObject>(fSession.getExecutor(), drm) {
@Override
protected void handleSuccess() {
+
getData().getChildrenCount(
- exprCtx,
- new DataRequestMonitor<Integer>(fSession.getExecutor(), drm) {
+ exprCtx, ((ExprMetaGetChildCount) command).getNumChildLimit(),
+ new DataRequestMonitor<ChildrenCountInfo>(fSession.getExecutor(), drm) {
@Override
protected void handleSuccess() {
- drm.setData(new ExprMetaGetChildCountInfo(getData()));
+ drm.setData(new ExprMetaGetChildCountInfo(
+ getData().getChildrenCount()));
drm.done();
processCommandDone(token, drm.getData());
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java
index 0daabfffee4..50b394e7f42 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
@@ -19,6 +20,7 @@ import org.eclipse.osgi.util.NLS;
class Messages extends NLS {
public static String Breakpoint_attribute_problem;
public static String Breakpoint_installation_failed;
+ public static String MIExpressions_NotAvailableBecauseChildOfDynamicVarobj;
static {
// initialize resource bundle
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties
index e04b5f77beb..8114e6d0e19 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties
@@ -7,7 +7,10 @@
#
# Contributors:
# Ericsson - initial API and implementation
+# Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
###############################################################################
Breakpoint_attribute_problem=Breakpoint attribute problem: {0}
Breakpoint_installation_failed=installation failed
+
+MIExpressions_NotAvailableBecauseChildOfDynamicVarobj=N/A (child of pretty-printed object)
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java
index aca7b0f37a8..1681b2fe7dd 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java
@@ -11,6 +11,7 @@
* Ericsson - Implementation for DSF-GDB
* Anna Dushistova (Mentor Graphics) - [318322] Add set solib-absolute-prefix
* Vladimir Prus (CodeSourcery) - Support for -data-read-memory-bytes (bug 322658)
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command;
@@ -36,6 +37,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoProgram;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoSharedLibrary;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoThreads;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIJump;
+import org.eclipse.cdt.dsf.mi.service.command.commands.CLIMaintenance;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIPasscount;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLIRecord;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLISource;
@@ -60,6 +62,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataListRegisterValues;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataReadMemory;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataReadMemoryBytes;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataWriteMemory;
+import org.eclipse.cdt.dsf.mi.service.command.commands.MIEnablePrettyPrinting;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIEnvironmentCD;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIEnvironmentDirectory;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIExecContinue;
@@ -133,6 +136,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarInfoPathExpression;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarInfoType;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarListChildren;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarSetFormat;
+import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarSetUpdateRange;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowAttributes;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowFormat;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarUpdate;
@@ -229,6 +233,11 @@ public class CommandFactory {
return new CLIJump(ctx, location);
}
+ /** @since 4.0 */
+ public ICommand<MIInfo> createCLIMaintenance(ICommandControlDMContext ctx, String subCommand) {
+ return new CLIMaintenance(ctx, subCommand);
+ }
+
public ICommand<MIInfo> createCLIPasscount(IBreakpointsTargetDMContext ctx, int breakpoint, int passcount) {
return new CLIPasscount(ctx, breakpoint, passcount);
}
@@ -375,6 +384,11 @@ public class CommandFactory {
return new MIDataWriteMemory(ctx, offset, address, wordFormat, wordSize, value);
}
+ /** @since 4.0 */
+ public ICommand<MIInfo> createMIEnablePrettyPrinting(ICommandControlDMContext ctx) {
+ return new MIEnablePrettyPrinting(ctx);
+ }
+
public ICommand<MIInfo> createMIEnvironmentCD(ICommandControlDMContext ctx, String path) {
return new MIEnvironmentCD(ctx, path);
}
@@ -801,10 +815,20 @@ public class CommandFactory {
return new MIVarListChildren(ctx, name);
}
+ /** @since 4.0 */
+ public ICommand<MIVarListChildrenInfo> createMIVarListChildren(ICommandControlDMContext ctx, String name, int from, int to) {
+ return new MIVarListChildren(ctx, name, from, to);
+ }
+
public ICommand<MIVarSetFormatInfo> createMIVarSetFormat(ICommandControlDMContext ctx, String name, String fmt) {
return new MIVarSetFormat(ctx, name, fmt);
}
+ /** @since 4.0 */
+ public ICommand<MIInfo> createMIVarSetUpdateRange(ICommandControlDMContext ctx,String name, int from, int to) {
+ return new MIVarSetUpdateRange(ctx, name, from, to);
+ }
+
public ICommand<MIVarShowAttributesInfo> createMIVarShowAttributes(ICommandControlDMContext ctx, String name) {
return new MIVarShowAttributes(ctx, name);
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIMaintenance.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIMaintenance.java
new file mode 100644
index 00000000000..6fa3ec1628c
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIMaintenance.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.mi.service.command.commands;
+
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
+
+/**
+ * Executes "maintenance" command.
+ * @since 4.0
+ */
+public class CLIMaintenance extends CLICommand<MIInfo> {
+
+ public CLIMaintenance(ICommandControlDMContext ctx, String arguments) {
+ super(ctx, "maintenance " + arguments); //$NON-NLS-1$
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildCount.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildCount.java
index 2241dc86c94..e3fc66a8e91 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildCount.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildCount.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2009 Ericsson and others.
+ * Copyright (c) 2007, 2010 Ericsson 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
@@ -7,15 +7,57 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.mi.service.IMIExpressions;
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetChildCountInfo;
public class ExprMetaGetChildCount extends ExprMetaCommand<ExprMetaGetChildCountInfo> {
+ private int numChildLimit = IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED;
+
public ExprMetaGetChildCount(IExpressionDMContext ctx) {
super(ctx);
}
+
+ /**
+ * @param ctx
+ * @param numChildLimit
+ *
+ * @since 4.0
+ */
+ public ExprMetaGetChildCount(IExpressionDMContext ctx, int numChildLimit) {
+ super(ctx);
+ this.numChildLimit = numChildLimit;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public int getNumChildLimit() {
+ return numChildLimit;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + numChildLimit;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ ExprMetaGetChildCount other = (ExprMetaGetChildCount) obj;
+ if (numChildLimit != other.numChildLimit)
+ return false;
+ return true;
+ }
} \ No newline at end of file
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildren.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildren.java
index 2c6c24e7cb9..16c1bb0a935 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildren.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/ExprMetaGetChildren.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2009 Ericsson and others.
+ * Copyright (c) 2007, 2010 Ericsson 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
@@ -7,15 +7,57 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.mi.service.IMIExpressions;
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetChildrenInfo;
public class ExprMetaGetChildren extends ExprMetaCommand<ExprMetaGetChildrenInfo> {
+ private int numChildLimit = IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED;
+
public ExprMetaGetChildren(IExpressionDMContext ctx) {
super(ctx);
}
+
+ /**
+ * @param ctx
+ * @param numChildLimit
+ *
+ * @since 4.0
+ */
+ public ExprMetaGetChildren(IExpressionDMContext ctx, int numChildLimit) {
+ super(ctx);
+ this.numChildLimit = numChildLimit;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public int getNumChildLimit() {
+ return numChildLimit;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + numChildLimit;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ ExprMetaGetChildren other = (ExprMetaGetChildren) obj;
+ if (numChildLimit != other.numChildLimit)
+ return false;
+ return true;
+ }
} \ No newline at end of file
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIEnablePrettyPrinting.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIEnablePrettyPrinting.java
new file mode 100644
index 00000000000..00fd6e31249
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIEnablePrettyPrinting.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.mi.service.command.commands;
+
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
+
+/**
+ * -enable-pretty-printing
+ *
+ * Enables Python based Pretty printing
+ *
+ * @since 4.0
+ */
+public class MIEnablePrettyPrinting extends MICommand<MIInfo>
+{
+ /**
+ * @param dmc
+ */
+ public MIEnablePrettyPrinting(ICommandControlDMContext dmc) {
+ super(dmc, "-enable-pretty-printing"); //$NON-NLS-1$
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoNumChildren.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoNumChildren.java
index 01d77951405..6cba555ec81 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoNumChildren.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoNumChildren.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 QNX Software Systems and others.
+ * Copyright (c) 2000, 2010 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* QNX Software Systems - Initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
@@ -17,12 +18,15 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIVarInfoNumChildrenInfo;
/**
*
- * -var-info-num-children NAME
- *
- * Returns the number of children of a variable object NAME:
- *
- * numchild=N
+ * -var-info-num-children NAME
+ *
+ * Returns the number of children of a variable object NAME:
+ *
+ * numchild=N
*
+ * Note that this number is not completely reliable for a dynamic varobjs. It
+ * will return the current number of children, but more children may be
+ * available.
*/
public class MIVarInfoNumChildren extends MICommand<MIVarInfoNumChildrenInfo>
{
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoPathExpression.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoPathExpression.java
index 62ea8a37140..c5ecbdc2acb 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoPathExpression.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarInfoPathExpression.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009 Ericsson and others.
+ * Copyright (c) 2009, 2010 Ericsson 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
@@ -7,6 +7,7 @@
*
* Contributors:
* Ericsson - Initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
@@ -25,7 +26,9 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIVarInfoPathExpressionInfo
*
* (gdb) -var-info-path-expression C.Base.public.m_size
* ^done,path_expr=((Base)c).m_size)
- *
+ *
+ * Cannot be used for dynamic varobjs, or varobjs that have a dynamic varobj
+ * as ancestor.
*/
public class MIVarInfoPathExpression extends MICommand<MIVarInfoPathExpressionInfo>
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarListChildren.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarListChildren.java
index fda2ffb856e..d2679e2967f 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarListChildren.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarListChildren.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009 QNX Software Systems and others.
+ * Copyright (c) 2009, 2010 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -8,6 +8,7 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
* Ericsson - Modified for handling of frame contexts
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.commands;
@@ -35,6 +36,21 @@ public class MIVarListChildren extends MICommand<MIVarListChildrenInfo>
public MIVarListChildren(ICommandControlDMContext ctx, String name) {
super(ctx, "-var-list-children", new String[]{name}); //$NON-NLS-1$
}
+
+ /**
+ * @param ctx
+ * @param name
+ * @param from
+ * The index of the first child to be listed, if there is one
+ * with this index.
+ * @param to
+ * One behind the last child to be listed.
+ *
+ * @since 4.0
+ */
+ public MIVarListChildren(ICommandControlDMContext ctx, String name, int from, int to) {
+ super(ctx, "-var-list-children", new String[]{name, String.valueOf(from), String.valueOf(to)}); //$NON-NLS-1$
+ }
@Override
public MIVarListChildrenInfo getResult(MIOutput out) {
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarSetUpdateRange.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarSetUpdateRange.java
new file mode 100644
index 00000000000..0134af22921
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIVarSetUpdateRange.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.mi.service.command.commands;
+
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
+
+/**
+ * -var-set-update-range name from to
+ *
+ * Set the range of children to be returned by future invocations of
+ * -var-update.
+ *
+ * <code>from</code> and <code>to</code> indicate the range of children to
+ * report in subsequent -var-update call. If from or to is less than zero, the
+ * range is reset and all children will be reported. Otherwise, children
+ * starting at from (zero-based) and up to and excluding to will be reported.
+ *
+ * @since 4.0
+ */
+public class MIVarSetUpdateRange extends MICommand<MIInfo> {
+
+ /**
+ * @param ctx
+ * @param name The name of the varobj for which the range is set.
+ * @param from Index of the first child to be updated with future -var-update.
+ * @param to One behind the last child to be updated.
+ */
+ public MIVarSetUpdateRange(ICommandControlDMContext ctx, String name, int from, int to) {
+ super(ctx, "-var-set-update-range", new String[]{name, String.valueOf(from), String.valueOf(to)}); //$NON-NLS-1$
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/ExprMetaGetVarInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/ExprMetaGetVarInfo.java
index 80054269978..6fc6fa6931f 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/ExprMetaGetVarInfo.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/ExprMetaGetVarInfo.java
@@ -7,21 +7,26 @@
*
* Contributors:
* Ericsson - initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
import org.eclipse.cdt.dsf.gdb.GDBTypeParser.GDBType;
+import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetChildCount;
public class ExprMetaGetVarInfo implements ICommandResult {
private final String expression;
- private final int numChild;
+ private final int numChildHint;
private final String type;
private final boolean editable;
private final GDBType gdbType;
-
+ /** If <code>true</code>, the variable is a collection, i.e. it may have children. */
+ private final boolean isCollectionHint;
+ private final boolean isSafeToAskForAllChildren;
+
public ExprMetaGetVarInfo(String e, int n, String t, boolean edit) {
this (e, n, t, null, edit);
}
@@ -30,30 +35,92 @@ public class ExprMetaGetVarInfo implements ICommandResult {
* @since 3.0
*/
public ExprMetaGetVarInfo(String e, int n, String t, GDBType gt, boolean edit) {
+ this(e, true, n, t, gt, edit, false);
+ }
+
+ /**
+ * @since 4.0
+ */
+ public ExprMetaGetVarInfo(String e, boolean isSafeToAskForAllChildren, int n,
+ String t, GDBType gt, boolean edit, boolean isCollectionHint) {
expression = e;
- numChild = n;
+ this.isSafeToAskForAllChildren = isSafeToAskForAllChildren;
+ numChildHint = n;
type = t;
editable = edit;
gdbType = gt;
+ this.isCollectionHint = isCollectionHint;
}
public String getExpr() { return expression; }
- public int getNumChildren() { return numChild; }
+
+ /**
+ * This method only returns a 'hint' to the number of children. In the case
+ * of C++ complex structures, this number will not be the actual number of
+ * children. This is because GDB considers 'private/protected/public' as an
+ * actual level of children, but we do not.
+ * In case of variable backed by a pretty printer, the number represents
+ * only the number of currently fetched children, not all children that
+ * might be available.
+ *
+ * @return The hint on the number of children.
+ *
+ * @deprecated Its not possible to tell the exact number of children, but
+ * you can use {@link #hasChildren()} in order to find out
+ * whether the variable has children at all. In order to find
+ * out about the correct number of children, use {@link ExprMetaGetChildCount}.
+ */
+ @Deprecated
+ public int getNumChildren() { return numChildHint; }
+
+ /**
+ * @return Whether the variable has children or not (reliable).
+ *
+ * @since 4.0
+ */
+ public boolean hasChildren() {
+ return (numChildHint > 0);
+ }
+
public String getType() { return type; }
+
/**
* @since 3.0
*/
public GDBType getGDBType() { return gdbType; }
+
public boolean getEditable() { return editable; }
-
+
+ /**
+ * @return If <code>true</code>, the variable is definitely a collection,
+ * if <code>false</code>, it's most probably not.
+ *
+ * @since 4.0
+ */
+ public boolean getCollectionHint() {
+ return isCollectionHint;
+ }
+
public <V extends ICommandResult> V getSubsetResult(ICommand<V> command) {
return null;
}
+ /**
+ * @return Whether this variable can be safely ask for all its children, or
+ * whether clients need to specify a limit on the number of children
+ * to be fetched, because otherwise the gdb might hang up.
+ *
+ * @since 4.0
+ */
+ public boolean isSafeToAskForAllChildren() {
+ return isSafeToAskForAllChildren;
+ }
+
@Override
public String toString() {
return getClass().getSimpleName() + " (" + //$NON-NLS-1$
getExpr() + ", " + getNumChildren() + ", " + //$NON-NLS-1$ //$NON-NLS-2$
- getType() + ", " + getEditable() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ getType() + ", " + getEditable() + ", " + //$NON-NLS-1$ //$NON-NLS-2$
+ getCollectionHint() + ")"; //$NON-NLS-1$
}
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIDisplayHint.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIDisplayHint.java
new file mode 100644
index 00000000000..2749dd81fc6
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIDisplayHint.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Verigy 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:
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.mi.service.command.output;
+
+/**
+ * Some utilities around the display hint provided by the python pretty printers
+ * via MI.
+ *
+ * @since 4.0
+ */
+public class MIDisplayHint {
+
+ public static final MIDisplayHint NONE = new MIDisplayHint(GdbDisplayHint.GDB_DISPLAY_HINT_NONE, ""); //$NON-NLS-1$
+
+ /**
+ * The set of display hints that are of particular interest to DSF GDB.
+ */
+ public enum GdbDisplayHint {
+
+ /**
+ * No hint given.
+ */
+ GDB_DISPLAY_HINT_NONE(null),
+
+ /**
+ * Display an expression or variable as string. Strings don't have children.
+ */
+ GDB_DISPLAY_HINT_STRING("string"), //$NON-NLS-1$
+
+ /**
+ * Display an expression or variable as array.
+ */
+ GDB_DISPLAY_HINT_ARRAY("array"), //$NON-NLS-1$
+
+ /**
+ * Display an expression or variable as map. This means each child with an
+ * odd index is a key, each child with an even index is the corresponding
+ * value.
+ */
+ GDB_DISPLAY_HINT_MAP("map"), //$NON-NLS-1$
+
+ /**
+ * A user defined hint. It has no further meaning to gdb.
+ */
+ GDB_DISPLAY_USER_DEFINED(null);
+
+ private final String miToken;
+
+ private GdbDisplayHint(String miToken) {
+ this.miToken = miToken;
+ }
+
+ /**
+ * @return The string that is used by MI to denote this display hint, if
+ * any.
+ */
+ public String getMIToken() {
+ return miToken;
+ }
+ }
+
+ private final GdbDisplayHint gdbHint;
+
+ private final String displayHint;
+
+ private MIDisplayHint(GdbDisplayHint gdbHint, String hint) {
+ this.gdbHint = gdbHint;
+ this.displayHint = hint;
+ }
+
+ /**
+ * Create the hint from the given string.
+ *
+ * @param text The string representation to parse in order to initialize from.
+ */
+ public MIDisplayHint(String text) {
+ gdbHint = parseDisplayHint(text);
+ displayHint = text.trim();
+ }
+
+ /**
+ * @return The display hint as returned by the pretty printer printer.
+ */
+ public String getDisplayHint() {
+ return displayHint;
+ }
+
+ /**
+ * @return One of the display hints that are of particular interest to DSF GDB.
+ */
+ public GdbDisplayHint getGdbDisplayHint() {
+ return gdbHint;
+ }
+
+ /**
+ * @return If <code>true</code>, the variable is definitely a collection,
+ * if <code>false</code>, it still might be a collection.
+ */
+ public boolean isCollectionHint() {
+ switch(getGdbDisplayHint()) {
+ case GDB_DISPLAY_HINT_ARRAY:
+ case GDB_DISPLAY_HINT_MAP:
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param text
+ * The snipped from the MI response.
+ * @return The decoded display hint predefined by gdb.
+ */
+ private static GdbDisplayHint parseDisplayHint(String text) {
+
+ String hint = text.trim();
+
+ for (GdbDisplayHint gdbHint : GdbDisplayHint.values()) {
+ String miToken = gdbHint.getMIToken();
+ if (miToken != null && miToken.equals(hint)) {
+ return gdbHint;
+ }
+ }
+
+ return GdbDisplayHint.GDB_DISPLAY_USER_DEFINED;
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVar.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVar.java
index b38329f0a4f..d9acba86612 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVar.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVar.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 QNX Software Systems and others.
+ * Copyright (c) 2000, 2010 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -8,28 +8,73 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
* Wind River Systems - Modified for new DSF Reference Implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
+
/**
* GDB/MI var-list-children
* -var-list-children var2
* ^done,numchild="6",children={child={name="var2.0",exp="0",numchild="0",type="char"},child={name="var2.1",exp="1",numchild="0",type="char"},child={name="var2.2",exp="2",numchild="0",type="char"},child={name="var2.3",exp="3",numchild="0",type="char"},child={name="var2.4",exp="4",numchild="0",type="char"},child={name="var2.5",exp="5",numchild="0",type="char"}}
- *
+ *
+ * -var-list-children var3
+ * ^done,numchild="3",displayhint="array",children=[child={name="var6.[0].[1]",exp="[1]",numchild="0",type="std::basic_string<char, std::char_traits<char>, std::allocator<char> >",thread-id="1"\
+,displayhint="string",dynamic="1"},child={name="var6.[0].[2]",exp="[2]",numchild="0",type="std::basic_string<char, std::char_traits<char>, std::allocator<char> >",thread-id="1",displayhint="string",dy\
+namic="1"},child={name="var6.[0].[3]",exp="[3]",numchild="0",type="std::basic_string<char, std::char_traits<char>, std::allocator<char> >",thread-id="1",displayhint="string",dynamic="1"}],has_more="0"\
*/
public class MIVar {
String name = ""; //$NON-NLS-1$
String type = ""; //$NON-NLS-1$
String exp = ""; //$NON-NLS-1$
+ private boolean isDynamic = false;
int numchild;
-
+ private boolean hasMore = false;
+ private MIDisplayHint displayHint = MIDisplayHint.NONE;
public MIVar(String n, int num, String t) {
+ this(n, false, num, false, t, MIDisplayHint.NONE);
+ }
+
+ /**
+ * @param n
+ * @param isDynamic
+ * @param num
+ * If isDynamic is true, the number of children currently fetched
+ * by gdb.
+ * @param hasMore
+ * If isDynamic is true, whether there are more children
+ * available than just <code>num</code>.
+ * @param t
+ *
+ * @since 4.0
+ */
+ public MIVar(String n, boolean isDynamic, int num, boolean hasMore, String t) {
+ this(n, isDynamic, num, hasMore, t, MIDisplayHint.NONE);
+ }
+
+ /**
+ * @param n
+ * @param isDynamic
+ * @param num
+ * If isDynamic is true, the number of children currently fetched
+ * by gdb.
+ * @param hasMore
+ * If isDynamic is true, whether there are more children
+ * available than just <code>num</code>.
+ * @param t
+ * @param displayHint
+ * @since 4.0
+ */
+ public MIVar(String n, boolean isDynamic, int num, boolean hasMore, String t, MIDisplayHint displayHint) {
name = n;
+ this.isDynamic = isDynamic;
numchild = num;
+ this.hasMore = hasMore;
type = t;
+ this.displayHint = displayHint;
}
public MIVar(MITuple tuple) {
@@ -44,14 +89,52 @@ public class MIVar {
return type;
}
+ /**
+ * @return Whether the value and children of this variable are provided
+ * by a pretty printer.
+ *
+ * @since 4.0
+ */
+ public boolean isDynamic() {
+ return isDynamic;
+ }
+
+ /**
+ * @return The number of children. If {@link #isDynamic()} returns true,
+ * the returned value only reflects the number of children currently
+ * fetched by gdb. Check {@link #hasMore()} in order to find out
+ * whether the are more children.
+ */
public int getNumChild() {
return numchild;
}
+ /**
+ * @return For dynamic varobjs ({@link #isDynamic() returns true} this
+ * method returns whether there are children in addition to the
+ * currently fetched, i.e. whether there are more children than
+ * {@link #getNumChild()} returns.
+ *
+ * @since 4.0
+ */
+ public boolean hasMore() {
+ return hasMore;
+ }
+
public String getExp() {
return exp;
}
+ /**
+ * @return Whether the underlying value conceptually represents a string,
+ * array, or map.
+ *
+ * @since 4.0
+ */
+ public MIDisplayHint getDisplayHint() {
+ return displayHint;
+ }
+
void parse(MITuple tuple) {
MIResult[] results = tuple.getMIResults();
for (int i = 0; i < results.length; i++) {
@@ -73,6 +156,12 @@ public class MIVar {
type = str;
} else if (var.equals("exp")) { //$NON-NLS-1$
exp = str;
+ } else if (var.equals("dynamic") && str.trim().equals("1")) { //$NON-NLS-1$ //$NON-NLS-2$
+ isDynamic = true;
+ } else if (var.equals("has_more") && str.trim().equals("1")) { //$NON-NLS-1$ //$NON-NLS-2$
+ hasMore = true;
+ } else if (var.equals("displayhint")) { //$NON-NLS-1$
+ displayHint = new MIDisplayHint(str);
}
}
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarChange.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarChange.java
index 933354a5969..dd5c45fc9d8 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarChange.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarChange.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 QNX Software Systems and others.
+ * Copyright (c) 2000, 2010 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,9 +7,11 @@
*
* Contributors:
* QNX Software Systems - Initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
+
/**
* GDB/MI var-update.
*/
@@ -19,7 +21,12 @@ public class MIVarChange {
String value;
boolean inScope;
boolean changed;
-
+ private boolean isDynamic = false;
+ private int newNumChildren = -1;
+ private boolean hasMore = false;
+ private MIVar[] newChildren;
+ private MIDisplayHint displayHint = MIDisplayHint.NONE;
+
public MIVarChange(String n) {
name = n;
}
@@ -40,6 +47,64 @@ public class MIVarChange {
return changed;
}
+ /**
+ * @return Whether the associated variable's value and children are provided
+ * by a pretty printer.
+ *
+ * @since 4.0
+ */
+ public boolean isDynamic() {
+ return isDynamic;
+ }
+
+ /**
+ * @return Whether the number of children changed since the last update.
+ *
+ * @since 4.0
+ */
+ public boolean numChildrenChanged() {
+ return (newNumChildren != -1);
+ }
+
+ /**
+ * Only call if {@link #numChildrenChanged()} returns true.
+ *
+ * @return The new number of children the associated varobj now has already fetched.
+ *
+ * @since 4.0
+ */
+ public int getNewNumChildren() {
+ assert(newNumChildren != -1);
+ return newNumChildren;
+ }
+
+ /**
+ * @return Whether there more children available than {@link #getNewNumChildren()}.
+ *
+ * @since 4.0
+ */
+ public boolean hasMore() {
+ return hasMore;
+ }
+
+ /**
+ * @return The children added within the current update range.
+ *
+ * @since 4.0
+ */
+ public MIVar[] getNewChildren() {
+ return newChildren;
+ }
+
+ /**
+ * @return The new display hint
+ *
+ * @since 4.0
+ */
+ public MIDisplayHint getDisplayHint() {
+ return displayHint;
+ }
+
public void setValue(String v) {
value = v;
}
@@ -51,4 +116,41 @@ public class MIVarChange {
public void setChanged(boolean c) {
changed = c;
}
+
+ /**
+ * @since 4.0
+ */
+ public void setDynamic(boolean isDynamic) {
+ this.isDynamic = isDynamic;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public void setNewNumChildren(int newNumChildren) {
+ this.newNumChildren = newNumChildren;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public void setHasMore(boolean hasMore) {
+ this.hasMore = hasMore;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public void setNewChildren(MIVar[] newChildren) {
+ this.newChildren = newChildren;
+ }
+
+ /**
+ * @param hint
+ *
+ * @since 4.0
+ */
+ public void setDisplayHint(MIDisplayHint hint) {
+ displayHint = hint;
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarCreateInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarCreateInfo.java
index 2db675b1ab2..77bd416ffff 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarCreateInfo.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarCreateInfo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 QNX Software Systems and others.
+ * Copyright (c) 2000, 2010 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -8,10 +8,12 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
* Wind River Systems - Modified for new DSF Reference Implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
+
/**
* GDB/MI var-create.
* -var-create "-" * a
@@ -28,7 +30,10 @@ public class MIVarCreateInfo extends MIInfo {
String type = ""; //$NON-NLS-1$
MIVar child;
String value = null;
-
+ private boolean isDynamic = false;
+ private boolean hasMore = false;
+ private MIDisplayHint displayHint = MIDisplayHint.NONE;
+
public MIVarCreateInfo(MIOutput record) {
super(record);
if (isDone()) {
@@ -55,6 +60,12 @@ public class MIVarCreateInfo extends MIInfo {
type = str;
} else if (var.equals("value")) { //$NON-NLS-1$
value = str;
+ } else if (var.equals("dynamic") && str.trim().equals("1")) { //$NON-NLS-1$ //$NON-NLS-2$
+ isDynamic = true;
+ } else if (var.equals("has_more") && str.trim().equals("1")) { //$NON-NLS-1$ //$NON-NLS-2$
+ hasMore = true;
+ } else if (var.equals("displayhint")) { //$NON-NLS-1$
+ displayHint = new MIDisplayHint(str);
}
}
}
@@ -66,11 +77,39 @@ public class MIVarCreateInfo extends MIInfo {
return type;
}
+ /**
+ * @return Whether the created variable's value and children are provided
+ * by a pretty printer.
+ *
+ * @since 4.0
+ */
+ public boolean isDynamic() {
+ return isDynamic;
+ }
+
+ /**
+ * @return The number of children. If {@link #isDynamic()} returns true,
+ * the returned value only reflects the number of children currently
+ * fetched by gdb. Check {@link #hasMore()} in order to find out
+ * whether the are more children.
+ */
public int getNumChildren()
{
return numChild;
}
+ /**
+ * @return For dynamic varobjs ({@link #isDynamic() returns true} this
+ * method returns whether there are children in addition to the
+ * currently fetched, i.e. whether there are more children than
+ * {@link #getNumChildren()} returns.
+ *
+ * @since 4.0
+ */
+ public boolean hasMore() {
+ return hasMore;
+ }
+
public String getName()
{
return name;
@@ -80,10 +119,20 @@ public class MIVarCreateInfo extends MIInfo {
{
return value;
}
+
+ /**
+ * @return Whether the underlying value conceptually represents a string,
+ * array, or map.
+ *
+ * @since 4.0
+ */
+ public MIDisplayHint getDisplayHint() {
+ return displayHint;
+ }
public MIVar getMIVar() {
if (child == null) {
- child = new MIVar(name, numChild, type);
+ child = new MIVar(name, isDynamic, numChild, hasMore, type, displayHint);
}
return child;
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarInfoNumChildrenInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarInfoNumChildrenInfo.java
index 7bb832d1345..f4c2a911953 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarInfoNumChildrenInfo.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarInfoNumChildrenInfo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 QNX Software Systems and others.
+ * Copyright (c) 2000, 2010 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* QNX Software Systems - Initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
@@ -14,6 +15,9 @@ package org.eclipse.cdt.dsf.mi.service.command.output;
/**
* GDB/MI var-info-num-children.
+ *
+ * For dynamic variable objects, only the number children currently fetched
+ * by gdb is returned.
*/
public class MIVarInfoNumChildrenInfo extends MIInfo {
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarListChildrenInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarListChildrenInfo.java
index 8fe8ab79486..bc99cdcd113 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarListChildrenInfo.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarListChildrenInfo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 QNX Software Systems and others.
+ * Copyright (c) 2000, 2010 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* QNX Software Systems - Initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
@@ -23,7 +24,8 @@ public class MIVarListChildrenInfo extends MIInfo {
MIVar[] children;
int numchild;
-
+ private boolean hasMore = false;
+
public MIVarListChildrenInfo(MIOutput record) {
super(record);
List<MIVar> aList = new ArrayList<MIVar>();
@@ -46,7 +48,14 @@ public class MIVarListChildrenInfo extends MIInfo {
}
} else if (var.equals("children")) { //$NON-NLS-1$
parseChildren(value, aList);
- }
+ } else if (var.equals("has_more")) { //$NON-NLS-1$
+ if (value instanceof MIConst) {
+ String str = ((MIConst) value).getString();
+ if (str.trim().equals("1")) { //$NON-NLS-1$
+ hasMore = true;
+ }
+ }
+ }
}
}
}
@@ -57,6 +66,15 @@ public class MIVarListChildrenInfo extends MIInfo {
return children;
}
+ /**
+ * @return Whether the are more children to fetch.
+ *
+ * @since 4.0
+ */
+ public boolean hasMore() {
+ return hasMore;
+ }
+
/*
* Some gdb MacOSX do not return a MITuple so we have
* to check for different format.
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarUpdateInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarUpdateInfo.java
index 8ae196f640a..78438adcec4 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarUpdateInfo.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIVarUpdateInfo.java
@@ -7,6 +7,7 @@
*
* Contributors:
* QNX Software Systems - Initial API and implementation
+ * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.output;
@@ -98,7 +99,45 @@ public class MIVarUpdateInfo extends MIInfo {
if (change != null) {
change.setChanged("true".equals(str)); //$NON-NLS-1$
}
- }
+ } else if (var.equals("new_num_children")) { //$NON-NLS-1$
+ if (change != null) {
+ try {
+ change.setNewNumChildren(Integer.parseInt(str.trim()));
+ } catch (NumberFormatException e) {
+ change.setNewNumChildren(0);
+ }
+ }
+ } else if (var.equals("dynamic")) { //$NON-NLS-1$
+ if (change != null) {
+ change.setDynamic(str.trim().equals("1")); //$NON-NLS-1$
+ }
+ } else if (var.equals("has_more")) { //$NON-NLS-1$
+ if (change != null) {
+ change.setHasMore(str.trim().equals("1")); //$NON-NLS-1$
+ }
+ } else if (var.equals("new_children")) { //$NON-NLS-1$
+ if (change != null) {
+ List<MIVar> newChildren = new ArrayList<MIVar>();
+ parseNewChildren(value, newChildren);
+ change.setNewChildren(newChildren.toArray(new MIVar[newChildren.size()]));
+ }
+ } else if (var.equals("displayhint")) { //$NON-NLS-1$
+ if (change != null) {
+ change.setDisplayHint(new MIDisplayHint(str));
+ }
+ }
+ }
+ }
+ }
+
+ private void parseNewChildren(MIValue value, List<MIVar> aList) {
+ if (value instanceof MIList) {
+ MIValue[] children = ((MIList)value).getMIValues();
+
+ for (MIValue child : children) {
+ if (child instanceof MITuple) {
+ aList.add(new MIVar((MITuple)child));
+ }
}
}
}

Back to the top