1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-22 22:22:11 +02:00

Bug 302121: Fully support gdb pretty printers

This commit is contained in:
Marc Khouzam 2010-11-05 01:28:52 +00:00
parent 2031a8ee15
commit 1ffc84fb58
40 changed files with 3373 additions and 278 deletions

View file

@ -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

View file

@ -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>

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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);
}
});
}
}
}

View file

@ -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();
@ -122,6 +182,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
*/
@ -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();
}
}

View file

@ -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);
}
});
}
}
}

View file

@ -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...>

View file

@ -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;
}

View file

@ -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$

View file

@ -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$
@ -181,6 +185,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

View file

@ -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();
}
}

View file

@ -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));
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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);
}

View file

@ -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$
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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$
}
}

View file

@ -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>
{

View file

@ -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>

View file

@ -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) {

View file

@ -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$
}
}

View file

@ -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$
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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.

View file

@ -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));
}
}
}
}