From 3ab1678bc370c56cb41f6830a872e806555ef61a Mon Sep 17 00:00:00 2001 From: Alvaro Sanchez-Leon Date: Fri, 24 Oct 2014 11:42:04 -0400 Subject: [PATCH] Bug 235747: [registers] Allow user to edit the register groups. Bug 235747: Move register group actions to the command framework. Change-Id: Ife5aefc1a1609309724db01d92a35750e25def24 Signed-off-by: Alvaro Sanchez-Leon Signed-off-by: Marc Khouzam Reviewed-on: https://git.eclipse.org/r/13980 Tested-by: Hudson CI --- .../META-INF/MANIFEST.MF | 20 +- debug/org.eclipse.cdt.debug.core/pom.xml | 2 +- .../core/model/IAddRegisterGroupHandler.java | 21 + .../core/model/IEditRegisterGroupHandler.java | 21 + .../model/IRemoveRegisterGroupsHandler.java | 20 + .../model/IRestoreRegisterGroupsHandler.java | 20 + .../core/RegisterGroupsPersistance.java | 263 +++ .../core/model/IRegisterGroupDescriptor.java | 35 + .../plugin.properties | 18 +- debug/org.eclipse.cdt.debug.ui/plugin.xml | 198 ++- .../actions/AbstractViewActionDelegate.java | 4 +- .../ui/actions/ActionMessages.properties | 4 +- .../AddRegisterGroupActionDelegate.java | 91 - .../EditRegisterGroupActionDelegate.java | 82 - .../RemoveRegisterGroupActionDelegate.java | 87 - ...reDefaultRegisterGroupsActionDelegate.java | 70 - .../AbstractRegisterGroupCommandHandler.java | 169 ++ .../AddRegisterGroupCommandHandler.java | 45 + .../EditRegisterGroupCommandHandler.java | 45 + .../RemoveRegisterGroupsCommandHandler.java | 45 + .../RestoreRegisterGroupsCommandHandler.java | 45 + .../GDBPatternMatchingExpressions.java | 62 +- .../cdt/dsf/gdb/service/GDBRegisters.java | 1137 +++++++++++++ .../gdb/service/GdbDebugServicesFactory.java | 4 +- .../eclipse/cdt/dsf/gdb/service/Messages.java | 6 +- .../cdt/dsf/gdb/service/Messages.properties | 6 +- .../cdt/dsf/mi/service/MIRegisters.java | 174 +- .../eclipse/cdt/dsf/mi/service/Messages.java | 5 +- .../cdt/dsf/mi/service/Messages.properties | 7 +- .../dsf/gdb/framework/ServiceEventWaitor.java | 39 +- .../GDBPatternMatchingExpressionsTest.java | 58 +- .../tests/dsf/gdb/tests/MIRegistersTest.java | 1492 ++++++++++++----- dsf/org.eclipse.cdt.dsf.ui/plugin.xml | 66 +- .../cdt/dsf/debug/internal/ui/Messages.java | 11 +- .../dsf/debug/internal/ui/Messages.properties | 12 +- .../AbstractDsfRegisterGroupActions.java | 1010 +++++++++++ .../actions/DsfAddRegisterGroupCommand.java | 48 + .../actions/DsfEditRegisterGroupCommand.java | 48 + .../DsfRemoveRegisterGroupsCommand.java | 48 + .../DsfRestoreRegisterGroupsCommand.java | 48 + .../cdt/dsf/internal/ui/DsfUIPlugin.java | 19 +- .../cdt/dsf/debug/service/IRegisters2.java | 90 + 42 files changed, 4758 insertions(+), 937 deletions(-) create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IAddRegisterGroupHandler.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IEditRegisterGroupHandler.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IRemoveRegisterGroupsHandler.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IRestoreRegisterGroupsHandler.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/RegisterGroupsPersistance.java create mode 100644 debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/IRegisterGroupDescriptor.java delete mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/AddRegisterGroupActionDelegate.java delete mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/EditRegisterGroupActionDelegate.java delete mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/RemoveRegisterGroupActionDelegate.java delete mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/RestoreDefaultRegisterGroupsActionDelegate.java create mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/AbstractRegisterGroupCommandHandler.java create mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/AddRegisterGroupCommandHandler.java create mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/EditRegisterGroupCommandHandler.java create mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/RemoveRegisterGroupsCommandHandler.java create mode 100644 debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/RestoreRegisterGroupsCommandHandler.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisters.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/AbstractDsfRegisterGroupActions.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfAddRegisterGroupCommand.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfEditRegisterGroupCommand.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfRemoveRegisterGroupsCommand.java create mode 100644 dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfRestoreRegisterGroupsCommand.java create mode 100644 dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters2.java diff --git a/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF b/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF index a2bfcf6e170..c1a8700f16e 100644 --- a/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF +++ b/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.debug.core; singleton:=true -Bundle-Version: 7.5.0.qualifier +Bundle-Version: 7.6.0.qualifier Bundle-Activator: org.eclipse.cdt.debug.core.CDebugCorePlugin Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -16,20 +16,28 @@ Export-Package: org.eclipse.cdt.debug.core, org.eclipse.cdt.debug.core.disassembly, org.eclipse.cdt.debug.core.executables, org.eclipse.cdt.debug.core.model, - org.eclipse.cdt.debug.core.model.provisional;x-friends:="org.eclipse.cdt.dsf,org.eclipse.cdt.debug.ui.memory.memorybrowser,org.eclipse.cdt.dsf.gdb,org.eclipse.cdt.debug.ui.memory.traditional", + org.eclipse.cdt.debug.core.model.provisional; + x-friends:="org.eclipse.cdt.dsf, + org.eclipse.cdt.debug.ui.memory.memorybrowser, + org.eclipse.cdt.dsf.gdb, + org.eclipse.cdt.debug.ui.memory.traditional", org.eclipse.cdt.debug.core.sourcelookup, - org.eclipse.cdt.debug.internal.core;x-friends:="org.eclipse.cdt.dsf.gdb,org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.dsf,org.eclipse.cdt.dsf.ui", + org.eclipse.cdt.debug.internal.core; + x-friends:="org.eclipse.cdt.dsf.gdb, + org.eclipse.cdt.dsf.gdb.ui, + org.eclipse.cdt.dsf, + org.eclipse.cdt.dsf.ui", org.eclipse.cdt.debug.internal.core.breakpoints;x-friends:="org.eclipse.cdt.debug.edc,org.eclipse.cdt.dsf.gdb", org.eclipse.cdt.debug.internal.core.disassembly;x-internal:=true, org.eclipse.cdt.debug.internal.core.executables;x-internal:=true, - org.eclipse.cdt.debug.internal.core.model;x-internal:=true, - org.eclipse.cdt.debug.internal.core.srcfinder;x-internal:=true, + org.eclipse.cdt.debug.internal.core.model;x-friends:="org.eclipse.cdt.dsf.ui,org.eclipse.cdt.dsf.gdb", org.eclipse.cdt.debug.internal.core.sourcelookup; x-friends:="org.eclipse.cdt.dsf.ui, org.eclipse.cdt.debug.edc, org.eclipse.cdt.debug.gdbjtag.core, org.eclipse.cdt.dsf.gdb, - org.eclipse.cdt.dsf" + org.eclipse.cdt.dsf", + org.eclipse.cdt.debug.internal.core.srcfinder;x-internal:=true Require-Bundle: org.eclipse.core.resources;bundle-version="[3.2.0,4.0.0)", org.eclipse.debug.core;bundle-version="[3.2.0,4.0.0)", org.eclipse.cdt.core;bundle-version="[5.0.0,6.0.0)", diff --git a/debug/org.eclipse.cdt.debug.core/pom.xml b/debug/org.eclipse.cdt.debug.core/pom.xml index 9de6ccb176f..bc8d0d3dadf 100644 --- a/debug/org.eclipse.cdt.debug.core/pom.xml +++ b/debug/org.eclipse.cdt.debug.core/pom.xml @@ -11,7 +11,7 @@ ../../pom.xml - 7.5.0-SNAPSHOT + 7.6.0-SNAPSHOT org.eclipse.cdt.debug.core eclipse-plugin diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IAddRegisterGroupHandler.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IAddRegisterGroupHandler.java new file mode 100644 index 00000000000..1e402ad491b --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IAddRegisterGroupHandler.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.core.model; + +import org.eclipse.debug.core.commands.IDebugCommandHandler; + +/** + * Handler interface to for the addRegisterGroup command + * + * @since 7.6 + */ +public interface IAddRegisterGroupHandler extends IDebugCommandHandler { +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IEditRegisterGroupHandler.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IEditRegisterGroupHandler.java new file mode 100644 index 00000000000..721c7e2eec0 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IEditRegisterGroupHandler.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.core.model; + +import org.eclipse.debug.core.commands.IDebugCommandHandler; + +/** + * Handler interface to for the editRegisterGroup command + * @since 7.6 + */ +public interface IEditRegisterGroupHandler extends IDebugCommandHandler { +} + diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IRemoveRegisterGroupsHandler.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IRemoveRegisterGroupsHandler.java new file mode 100644 index 00000000000..b8c77e9a989 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IRemoveRegisterGroupsHandler.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.core.model; + +import org.eclipse.debug.core.commands.IDebugCommandHandler; + +/** + * Handler interface to for the removeRegisterGroups command + * @since 7.6 + */ +public interface IRemoveRegisterGroupsHandler extends IDebugCommandHandler { +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IRestoreRegisterGroupsHandler.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IRestoreRegisterGroupsHandler.java new file mode 100644 index 00000000000..56d9ef748a5 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IRestoreRegisterGroupsHandler.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.core.model; + +import org.eclipse.debug.core.commands.IDebugCommandHandler; + +/** + * Handler interface to for the restoreRegisterGroups command + * @since 7.6 + */ +public interface IRestoreRegisterGroupsHandler extends IDebugCommandHandler { +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/RegisterGroupsPersistance.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/RegisterGroupsPersistance.java new file mode 100644 index 00000000000..2a811c7b9a8 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/RegisterGroupsPersistance.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2000, 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation in CRegisterManager.java and CRegisterGroup.java + * Alvaro Sanchez-Leon (Ericsson) - Integrated from files above for Bug 235747 + *******************************************************************************/ + +package org.eclipse.cdt.debug.internal.core; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.debug.core.model.IRegisterDescriptor; +import org.eclipse.cdt.debug.internal.core.model.CoreModelMessages; +import org.eclipse.cdt.debug.internal.core.model.IRegisterGroupDescriptor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +public class RegisterGroupsPersistance { + private static final String BLANK_STRING = ""; //$NON-NLS-1$ + private static final String DEFAULT_LAUNCH_CONFIGURATION_TARGET_ATTRIBUTE = ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_REGISTER_GROUPS; + private static final String ELEMENT_REGISTER_GROUP_LIST = "registerGroups"; //$NON-NLS-1$ + private static final String ATTR_REGISTER_GROUP_MEMENTO = "memento"; //$NON-NLS-1$ + + private static final String ELEMENT_GROUP = "group"; //$NON-NLS-1$ + private static final String ELEMENT_REGISTER_GROUP = "registerGroup"; //$NON-NLS-1$ + private static final String ATTR_REGISTER_GROUP_NAME = "name"; //$NON-NLS-1$ + private static final String ATTR_REGISTER_GROUP_ENABLED = "enabled"; //$NON-NLS-1$ + + private static final String ELEMENT_REGISTER = "register"; //$NON-NLS-1$ + + private static final String ATTR_REGISTER_NAME = "name"; //$NON-NLS-1$ + private static final String ATTR_REGISTER_ORIGINAL_GROUP_NAME = "originalGroupName"; //$NON-NLS-1$ + + private final ILaunchConfiguration fLaunchConfig; + + private String fLaunchConfigTargetAttribute = DEFAULT_LAUNCH_CONFIGURATION_TARGET_ATTRIBUTE; + + // Constructor + public RegisterGroupsPersistance(ILaunchConfiguration configuration) { + fLaunchConfig = configuration; + } + + private class RegisterGroupDescriptor implements IRegisterGroupDescriptor { + + private final String fMemento; + private final String fName; + private final boolean fEnabled; + IRegisterDescriptor[] fRegisterDescriptors = null; + + public RegisterGroupDescriptor(String memento, String groupName, boolean enabled) { + fMemento = memento; + fName = groupName; + fEnabled = enabled; + } + + @Override + public String getName() { + return fName; + } + + @Override + public boolean isEnabled() { + return fEnabled; + } + + @Override + public IRegisterDescriptor[] getChildren() throws CoreException { + if (fRegisterDescriptors == null) { + + Node node = DebugPlugin.parseDocument(fMemento); + Element element = (Element) node; + + List list = new ArrayList(); + Node childNode = element.getFirstChild(); + while (childNode != null) { + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + Element child = (Element) childNode; + if (ELEMENT_REGISTER.equals(child.getNodeName())) { + String name = child.getAttribute(ATTR_REGISTER_NAME); + String originalGroupName = child.getAttribute(ATTR_REGISTER_ORIGINAL_GROUP_NAME); + if (name == null || name.length() == 0 || originalGroupName == null + || originalGroupName.length() == 0) { + abort(CoreModelMessages.getString("CRegisterGroup.3"), null); //$NON-NLS-1$ + } else { + IRegisterDescriptor d = findDescriptor(originalGroupName, name); + if (d != null) + list.add(d); + else + CDebugCorePlugin.log(CoreModelMessages.getString("CRegisterGroup.4")); //$NON-NLS-1$ + } + } + } + childNode = childNode.getNextSibling(); + } + + fRegisterDescriptors = list.toArray(new IRegisterDescriptor[list.size()]); + } + + return fRegisterDescriptors; + } + + } + + class RegisterDescriptor implements IRegisterDescriptor { + private final String fGroupName; + private final String fName; + + private RegisterDescriptor(String oGroupName, String rname) { + fGroupName = oGroupName; + fName = rname; + } + + @Override + public String getName() { + return fName; + } + + @Override + public String getGroupName() { + return fGroupName; + } + } + + public void setLaunchConfigurationTargetAttribute(String launchConfigurationTargetAttribute) { + fLaunchConfigTargetAttribute = launchConfigurationTargetAttribute; + } + + public String getLaunchConfigurationTargetAttribute() { + + return fLaunchConfigTargetAttribute; + } + + public IRegisterGroupDescriptor[] parseGroups() { + List groups = new ArrayList(); + String memento; + try { + memento = fLaunchConfig.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_REGISTER_GROUPS, BLANK_STRING); + + if (memento != null && memento.length() > 0) { + Node node = DebugPlugin.parseDocument(memento); + + if (node.getNodeType() != Node.ELEMENT_NODE) { + abort("Unable to restore register groups - invalid memento.", null); //$NON-NLS-1$ + } + Element element = (Element) node; + if (!ELEMENT_REGISTER_GROUP_LIST.equals(element.getNodeName())) { + abort("Unable to restore register groups - expecting register group list element.", null); //$NON-NLS-1$ + } + + Node childNode = element.getFirstChild(); + while (childNode != null) { + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + Element child = (Element) childNode; + if (ELEMENT_GROUP.equals(child.getNodeName())) { + String groupMemento = child.getAttribute(ATTR_REGISTER_GROUP_MEMENTO); + // + IRegisterGroupDescriptor groupdesc = createGroupFromMemento(groupMemento); + if (groupdesc != null) { + groups.add(groupdesc); + } + } + } + childNode = childNode.getNextSibling(); + } + + } + } catch (CoreException e) { + + e.printStackTrace(); + } + + return groups.toArray(new IRegisterGroupDescriptor[groups.size()]); + + } + + public void saveGroups(IRegisterGroupDescriptor[] groups) throws CoreException { + try { + ILaunchConfigurationWorkingCopy wc = fLaunchConfig.getWorkingCopy(); + + //if no groups present, save to a blank string, i.e. expected by CDI and handled by DSF + wc.setAttribute(fLaunchConfigTargetAttribute, (groups.length > 0) ? getMemento(groups) : BLANK_STRING); + wc.doSave(); + } catch (CoreException e) { + abort(e.getMessage() + ", cause: " + e.getCause(), e); //$NON-NLS-1$ + } + } + + protected IRegisterDescriptor findDescriptor(String originalGroupName, String name) { + return new RegisterDescriptor(originalGroupName, name); + } + + private IRegisterGroupDescriptor createGroupFromMemento(String memento) throws CoreException { + Node node = DebugPlugin.parseDocument(memento); + if (node.getNodeType() != Node.ELEMENT_NODE) { + abort(CoreModelMessages.getString("CRegisterGroup.0"), null); //$NON-NLS-1$ + } + Element element = (Element) node; + if (!ELEMENT_REGISTER_GROUP.equals(element.getNodeName())) { + abort(CoreModelMessages.getString("CRegisterGroup.1"), null); //$NON-NLS-1$ + } + String groupName = element.getAttribute(ATTR_REGISTER_GROUP_NAME); + if (groupName == null || groupName.length() == 0) { + abort(CoreModelMessages.getString("CRegisterGroup.2"), null); //$NON-NLS-1$ + } + String e = element.getAttribute(ATTR_REGISTER_GROUP_ENABLED); + boolean enabled = Boolean.parseBoolean(e); + + IRegisterGroupDescriptor group = new RegisterGroupDescriptor(memento, groupName, enabled); + + return group; + } + + private String getMemento(IRegisterGroupDescriptor[] groups) throws CoreException { + Document document = DebugPlugin.newDocument(); + Element element = document.createElement(ELEMENT_REGISTER_GROUP_LIST); + for (IRegisterGroupDescriptor group : groups) { + Element child = document.createElement(ELEMENT_GROUP); + child.setAttribute(ATTR_REGISTER_GROUP_MEMENTO, getMemento(group)); + element.appendChild(child); + } + + document.appendChild(element); + return DebugPlugin.serializeDocument(document); + } + + private String getMemento(IRegisterGroupDescriptor group) throws CoreException { + Document document = DebugPlugin.newDocument(); + Element element = document.createElement(ELEMENT_REGISTER_GROUP); + element.setAttribute(ATTR_REGISTER_GROUP_NAME, group.getName()); + element.setAttribute(ATTR_REGISTER_GROUP_ENABLED, Boolean.valueOf(group.isEnabled()).toString()); + IRegisterDescriptor[] registerDescriptors = group.getChildren(); + for (int i = 0; i < registerDescriptors.length; ++i) { + Element child = document.createElement(ELEMENT_REGISTER); + child.setAttribute(ATTR_REGISTER_NAME, registerDescriptors[i].getName()); + child.setAttribute(ATTR_REGISTER_ORIGINAL_GROUP_NAME, registerDescriptors[i].getGroupName()); + element.appendChild(child); + } + + document.appendChild(element); + return DebugPlugin.serializeDocument(document); + } + + private void abort(String message, Throwable exception) throws CoreException { + IStatus status = new Status(IStatus.ERROR, CDebugCorePlugin.PLUGIN_ID, IStatus.ERROR, message, exception); + throw new CoreException(status); + } + +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/IRegisterGroupDescriptor.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/IRegisterGroupDescriptor.java new file mode 100644 index 00000000000..ff72c97a26b --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/IRegisterGroupDescriptor.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson AB 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: + * Alvaro Sanchez-Leon (Ericsson) - First Implementation and API (Bug 235747) + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.core.model; + +import org.eclipse.cdt.debug.core.model.IRegisterDescriptor; +import org.eclipse.core.runtime.CoreException; + +/** + * Describes a register Group + */ +public interface IRegisterGroupDescriptor { + /** + * @return the register group's name + */ + public String getName(); + + /** + * @return the enabled state + */ + public boolean isEnabled(); + + /** + * @return the registers associated to this group + * @throws CoreException + */ + public IRegisterDescriptor[] getChildren() throws CoreException; +} diff --git a/debug/org.eclipse.cdt.debug.ui/plugin.properties b/debug/org.eclipse.cdt.debug.ui/plugin.properties index 2fda45869f0..3daa217a7df 100644 --- a/debug/org.eclipse.cdt.debug.ui/plugin.properties +++ b/debug/org.eclipse.cdt.debug.ui/plugin.properties @@ -142,12 +142,26 @@ ModulesDetailPaneFontDefinition.description=The text font used in the detail pan ModulePropertiesAction.label=Properties... ModulePropertiesAction.tooltip=Open Module Properties Dialog +RegisterGroupingCategory.description=Set of commands for Register Grouping +RegisterGroupingCategory.name=Register Grouping commands +AddRegisterGroup.description=Adds a Register Group +AddRegisterGroup.name=Add RegisterGroup +AddRegisterGroup.label=Add Register Group AddRegisterGroupAction.label=Add Register Group AddRegisterGroupAction.tooltip=Add Register Group -RemoveRegisterGroupAction.label=Remove Register Group -RemoveRegisterGroupAction.tooltip=Remove Register Group +RemoveRegisterGroups.description=Removes one or more Register Groups +RemoveRegisterGroups.name=Remove Register Groups +RemoveRegisterGroups.label=Remove Register Groups +RemoveRegisterGroupsAction.label=Remove Register Groups +RemoveRegisterGroupsAction.tooltip=Remove Register Groups +EditRegisterGroup.description=Edits a Register Group +EditRegisterGroup.name=Edit Register Group +EditRegisterGroup.label=Edit Register Group EditRegisterGroupAction.label=Edit Register Group EditRegisterGroupAction.tooltip=Edit Register Group +RestoreRegisterGroups.description=Restores the Default Register Groups +RestoreRegisterGroups.name=Restore Default Register Groups +RestoreRegisterGroups.label=Restore Default Register Groups RestoredefaultRegisterGroupsAction.label=Restore Default Register Groups RestoredefaultRegisterGroupsAction.tooltip=Restore Default Register Groups diff --git a/debug/org.eclipse.cdt.debug.ui/plugin.xml b/debug/org.eclipse.cdt.debug.ui/plugin.xml index ac39c567516..0b58b5245ec 100644 --- a/debug/org.eclipse.cdt.debug.ui/plugin.xml +++ b/debug/org.eclipse.cdt.debug.ui/plugin.xml @@ -798,34 +798,6 @@ class="org.eclipse.cdt.debug.core.model.ICVariable"> - - - - - - - - - - - - - - @@ -1395,18 +1346,14 @@ - - + - - + @@ -1964,6 +1911,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2279,6 +2325,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/AbstractViewActionDelegate.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/AbstractViewActionDelegate.java index e64b23b7fc2..e15e7892787 100644 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/AbstractViewActionDelegate.java +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/AbstractViewActionDelegate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2007 QNX Software Systems and others. + * Copyright (c) 2004, 2014 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 + * Alvaro Sanchez-Leon (Ericsson) - preserve selection changes (needed by Bug 235747) *******************************************************************************/ package org.eclipse.cdt.debug.internal.ui.actions; @@ -187,6 +188,7 @@ public abstract class AbstractViewActionDelegate extends ActionDelegate implemen */ @Override public void selectionChanged( IAction action, ISelection selection ) { + setSelection( selection ); update(); } diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/ActionMessages.properties b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/ActionMessages.properties index db038c6df1d..c2060af77cf 100644 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/ActionMessages.properties +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/ActionMessages.properties @@ -11,6 +11,7 @@ # Marc Khouzam (Ericsson) - Added dynamic printf support (400628) # Simon Marchi (Ericsson) - Modified error messages in CastToArrayActionDelegate (437182) # Marc Dumais (Ericsson) - Bug 437692 +# Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747) ############################################################################### LoadSymbolsActionDelegate.Unable_to_load_symbols_of_shared_library_1=Unable to load symbols of shared library. @@ -119,9 +120,10 @@ ToggleDetailPaneAction.4=Place the Detail Pane on the Right of the Main Tree Vie ToggleDetailPaneAction.5=Place the Detail Pane on the Right of the Main Tree View ToggleDetailPaneAction.6=Hide the Detail Pane so that only the Main Tree View is Visible ToggleDetailPaneAction.7=Hide the Detail Pane so that only the Main Tree View is Visible -AddRegisterGroupActionDelegate.0=Error +RegisterGroupActionDelegate.0=Error AddRegisterGroupActionDelegate.1=Error(s) occurred adding register group. EditRegisterGroupActionDelegate.0=Unable to edit register group. +RemoveRegisterGroupsActionDelegate.0=Unable to remove register group(s). AddEventBreakpointActionDelegate.0=Error adding Event Breakpoint AddEventBreakpointActionDelegate.2=Action is not supported by installed debuggers ToggleCBreakpointsTargetFactory.CBreakpointDescription=Standard C/C++ breakpoint type. diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/AddRegisterGroupActionDelegate.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/AddRegisterGroupActionDelegate.java deleted file mode 100644 index f673c7f09f8..00000000000 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/AddRegisterGroupActionDelegate.java +++ /dev/null @@ -1,91 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * QNX Software Systems - Initial API and implementation - *******************************************************************************/ -package org.eclipse.cdt.debug.internal.ui.actions; - -import org.eclipse.cdt.debug.core.model.ICDebugTarget; -import org.eclipse.debug.core.DebugEvent; -import org.eclipse.debug.core.DebugException; -import org.eclipse.debug.core.model.IDebugElement; -import org.eclipse.debug.ui.DebugUITools; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.window.Window; - -/** - * A delegate for the "Add register group" action. - */ -public class AddRegisterGroupActionDelegate extends AbstractViewActionDelegate { - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.internal.ui.actions.AbstractViewActionDelegate#getErrorDialogTitle() - */ - @Override - protected String getErrorDialogTitle() { - return ActionMessages.getString( "AddRegisterGroupActionDelegate.0" ); //$NON-NLS-1$ - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.internal.ui.actions.AbstractViewActionDelegate#getErrorDialogMessage() - */ - @Override - protected String getErrorDialogMessage() { - return ActionMessages.getString( "AddRegisterGroupActionDelegate.1" ); //$NON-NLS-1$ - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.internal.ui.actions.AbstractViewActionDelegate#doAction() - */ - @Override - protected void doAction() throws DebugException { - RegisterGroupDialog dialog = new RegisterGroupDialog( getView().getSite().getShell(), getDebugTarget().getRegisterDescriptors() ); - if ( dialog.open() == Window.OK ) { - getDebugTarget().addRegisterGroup( dialog.getName(), dialog.getDescriptors() ); - } - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.internal.ui.actions.AbstractViewActionDelegate#update() - */ - @Override - protected void update() { - IAction action = getAction(); - if ( action != null ) { - ICDebugTarget target = getDebugTarget(); - action.setEnabled( ( target != null ) ? target.isSuspended() : false ); - } - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.internal.ui.actions.AbstractViewActionDelegate#doHandleDebugEvent(org.eclipse.debug.core.DebugEvent) - */ - @Override - protected void doHandleDebugEvent( DebugEvent event ) { - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.internal.ui.actions.AbstractViewActionDelegate#init(org.eclipse.jface.action.IAction) - */ - @Override - public void init( IAction action ) { - super.init( action ); - Object element = DebugUITools.getDebugContext(); - setSelection( (element != null) ? new StructuredSelection( element ) : new StructuredSelection() ); - update(); - } - - private ICDebugTarget getDebugTarget() { - Object element = getSelection().getFirstElement(); - if ( element instanceof IDebugElement ) { - return (ICDebugTarget)((IDebugElement)element).getDebugTarget().getAdapter( ICDebugTarget.class ); - } - return null; - } -} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/EditRegisterGroupActionDelegate.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/EditRegisterGroupActionDelegate.java deleted file mode 100644 index f1b27ff9ae7..00000000000 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/EditRegisterGroupActionDelegate.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * QNX Software Systems - Initial API and implementation - *******************************************************************************/ -package org.eclipse.cdt.debug.internal.ui.actions; - -import org.eclipse.cdt.debug.core.model.ICDebugTarget; -import org.eclipse.cdt.debug.core.model.IPersistableRegisterGroup; -import org.eclipse.cdt.debug.core.model.IRegisterDescriptor; -import org.eclipse.cdt.debug.internal.core.model.CDebugTarget; -import org.eclipse.cdt.debug.ui.CDebugUIPlugin; -import org.eclipse.debug.core.DebugException; -import org.eclipse.debug.core.model.IDebugTarget; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.actions.ActionDelegate; - - -public class EditRegisterGroupActionDelegate extends ActionDelegate implements IObjectActionDelegate { - - private IPersistableRegisterGroup fSelection; - - /* (non-Javadoc) - * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart) - */ - @Override - public void setActivePart( IAction action, IWorkbenchPart targetPart ) { - } - - /* (non-Javadoc) - * @see org.eclipse.ui.actions.ActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection) - */ - @Override - public void selectionChanged( IAction action, ISelection selection ) { - if ( selection instanceof IStructuredSelection ) { - IStructuredSelection ss = (IStructuredSelection)selection; - if ( !ss.isEmpty() ) { - Object s = ss.getFirstElement(); - if ( s instanceof IPersistableRegisterGroup ) { - fSelection = (IPersistableRegisterGroup)s; - } - } - } - } - - private IPersistableRegisterGroup getRegisterGroup() { - return fSelection; - } - - /* (non-Javadoc) - * @see org.eclipse.ui.actions.ActionDelegate#run(org.eclipse.jface.action.IAction) - */ - @Override - public void run( IAction action ) { - IPersistableRegisterGroup group = getRegisterGroup(); - IRegisterDescriptor[] all; - try { - all = ((CDebugTarget)group.getDebugTarget()).getRegisterDescriptors(); - RegisterGroupDialog dialog = new RegisterGroupDialog( Display.getCurrent().getActiveShell(), group.getName(), all, group.getRegisterDescriptors() ); - if ( dialog.open() == Window.OK ) { - IDebugTarget target = group.getDebugTarget(); - if ( target instanceof ICDebugTarget ) { - ((ICDebugTarget)target).modifyRegisterGroup( group, dialog.getDescriptors() ); - } - } - } - catch( DebugException e ) { - CDebugUIPlugin.errorDialog( ActionMessages.getString( "EditRegisterGroupActionDelegate.0" ), e.getStatus() ); //$NON-NLS-1$ - } - } -} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/RemoveRegisterGroupActionDelegate.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/RemoveRegisterGroupActionDelegate.java deleted file mode 100644 index f35bddb93fa..00000000000 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/RemoveRegisterGroupActionDelegate.java +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * QNX Software Systems - Initial API and implementation - *******************************************************************************/ -package org.eclipse.cdt.debug.internal.ui.actions; - -import java.util.ArrayList; -import java.util.Iterator; -import org.eclipse.cdt.debug.core.model.ICDebugTarget; -import org.eclipse.debug.core.model.IDebugTarget; -import org.eclipse.debug.core.model.IRegisterGroup; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.ui.IObjectActionDelegate; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.actions.ActionDelegate; - -/** - * The "Remove Register Group" action. - */ -public class RemoveRegisterGroupActionDelegate extends ActionDelegate implements IObjectActionDelegate { - - private IRegisterGroup[] fRegisterGroups; - - /** - * Constructor for RemoveRegisterGroupActionDelegate. - */ - public RemoveRegisterGroupActionDelegate() { - super(); - setRegisterGroups( new IRegisterGroup[0] ); - } - - /* (non-Javadoc) - * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart) - */ - @Override - public void setActivePart( IAction action, IWorkbenchPart targetPart ) { - } - - /* (non-Javadoc) - * @see org.eclipse.ui.actions.ActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection) - */ - @Override - public void selectionChanged( IAction action, ISelection selection ) { - ArrayList list = new ArrayList(); - if ( selection instanceof IStructuredSelection ) { - IStructuredSelection ss = (IStructuredSelection)selection; - Iterator it = ss.iterator(); - while( it.hasNext() ) { - Object o = it.next(); - if ( o instanceof IRegisterGroup ) { - list.add( o ); - } - } - } - setRegisterGroups( (IRegisterGroup[])list.toArray( new IRegisterGroup[list.size()] ) ); - } - - protected IRegisterGroup[] getRegisterGroups() { - return fRegisterGroups; - } - - protected void setRegisterGroups( IRegisterGroup[] registerGroups ) { - fRegisterGroups = registerGroups; - } - - /* (non-Javadoc) - * @see org.eclipse.ui.actions.ActionDelegate#run(org.eclipse.jface.action.IAction) - */ - @Override - public void run( IAction action ) { - IRegisterGroup[] groups = getRegisterGroups(); - if ( groups.length > 0 ) { - IDebugTarget target = groups[0].getDebugTarget(); - if ( target instanceof ICDebugTarget ) { - ((ICDebugTarget)target).removeRegisterGroups( groups ); - } - } - } -} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/RestoreDefaultRegisterGroupsActionDelegate.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/RestoreDefaultRegisterGroupsActionDelegate.java deleted file mode 100644 index 62dd536590d..00000000000 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/actions/RestoreDefaultRegisterGroupsActionDelegate.java +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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 - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * QNX Software Systems - Initial API and implementation - *******************************************************************************/ -package org.eclipse.cdt.debug.internal.ui.actions; - -import org.eclipse.cdt.debug.core.model.ICDebugTarget; -import org.eclipse.debug.core.DebugEvent; -import org.eclipse.debug.core.DebugException; -import org.eclipse.debug.core.model.IDebugElement; -import org.eclipse.debug.ui.DebugUITools; -import org.eclipse.jface.action.IAction; -import org.eclipse.jface.viewers.StructuredSelection; - - -public class RestoreDefaultRegisterGroupsActionDelegate extends AbstractViewActionDelegate { - - @Override - protected String getErrorDialogTitle() { - return ActionMessages.getString( "RestoreDefaultRegisterGroupsActionDelegate.0" ); //$NON-NLS-1$ - } - - @Override - protected String getErrorDialogMessage() { - return ActionMessages.getString( "RestoreDefaultRegisterGroupsActionDelegate.1" ); //$NON-NLS-1$ - } - - @Override - protected void doAction() throws DebugException { - getDebugTarget().restoreDefaultRegisterGroups(); - } - - @Override - protected void update() { - IAction action = getAction(); - if ( action != null ) { - ICDebugTarget target = getDebugTarget(); - action.setEnabled( ( target != null ) ? target.isSuspended() : false ); - } - } - - @Override - protected void doHandleDebugEvent( DebugEvent event ) { - } - - private ICDebugTarget getDebugTarget() { - Object element = getSelection().getFirstElement(); - if ( element instanceof IDebugElement ) { - return (ICDebugTarget)((IDebugElement)element).getDebugTarget().getAdapter( ICDebugTarget.class ); - } - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.cdt.debug.internal.ui.actions.AbstractViewActionDelegate#init(org.eclipse.jface.action.IAction) - */ - @Override - public void init( IAction action ) { - super.init( action ); - Object element = DebugUITools.getDebugContext(); - setSelection( (element != null) ? new StructuredSelection( element ) : new StructuredSelection() ); - update(); - } -} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/AbstractRegisterGroupCommandHandler.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/AbstractRegisterGroupCommandHandler.java new file mode 100644 index 00000000000..53629e7bb1f --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/AbstractRegisterGroupCommandHandler.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2004, 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Alvaro Sanchez-Leon (Ericsson) - Support Register Groups (Bug 235747) + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.ui.commands; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.eclipse.cdt.debug.core.model.ICDebugTarget; +import org.eclipse.cdt.debug.core.model.IPersistableRegisterGroup; +import org.eclipse.cdt.debug.core.model.IRegisterDescriptor; +import org.eclipse.cdt.debug.internal.core.model.CDebugTarget; +import org.eclipse.cdt.debug.internal.ui.actions.ActionMessages; +import org.eclipse.cdt.debug.internal.ui.actions.RegisterGroupDialog; +import org.eclipse.cdt.debug.ui.CDebugUIPlugin; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IRegisterGroup; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Display; + +public abstract class AbstractRegisterGroupCommandHandler extends AbstractHandler { + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#addRegisterGroup(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + public void addRegisterGroup(IStructuredSelection selection) { + ICDebugTarget t = getDebugTarget(selection); + if (t != null) { + // Using Debug model + try { + IRegisterDescriptor[] registers = t.getRegisterDescriptors(); + RegisterGroupDialog dialog = new RegisterGroupDialog(Display.getCurrent().getActiveShell(), registers); + if (dialog.open() == Window.OK) { + t.addRegisterGroup(dialog.getName(), dialog.getDescriptors()); + } + } catch (DebugException e) { + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#canAddRegisterGroup(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + public boolean canAddRegisterGroup(IStructuredSelection selection) { + ICDebugTarget target = getDebugTarget(selection); + return (target != null) ? target.isSuspended() : false; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#editRegisterGroup(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + public void editRegisterGroup(IStructuredSelection selection) { + IPersistableRegisterGroup group = getRegisterGroup(selection); + if (group == null) { + return; + } + + IRegisterDescriptor[] all; + try { + all = ((CDebugTarget) group.getDebugTarget()).getRegisterDescriptors(); + RegisterGroupDialog dialog = new RegisterGroupDialog(Display.getCurrent().getActiveShell(), + group.getName(), all, group.getRegisterDescriptors()); + if (dialog.open() == Window.OK) { + IDebugTarget target = group.getDebugTarget(); + if (target instanceof ICDebugTarget) { + ((ICDebugTarget) target).modifyRegisterGroup(group, dialog.getDescriptors()); + } + } + } catch (DebugException e) { + CDebugUIPlugin.errorDialog(ActionMessages.getString("EditRegisterGroupActionDelegate.0"), e.getStatus()); //$NON-NLS-1$ + } + + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#canEditRegisterGroup(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + public boolean canEditRegisterGroup(IStructuredSelection selection) { + IPersistableRegisterGroup group = getRegisterGroup(selection); + return (group != null); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#removeRegisterGroups(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + public void removeRegisterGroups(IStructuredSelection selection) { + IRegisterGroup[] groups = getRegisterGroups(selection); + if (groups.length > 0) { + IDebugTarget target = groups[0].getDebugTarget(); + if (target instanceof ICDebugTarget) { + ((ICDebugTarget) target).removeRegisterGroups(groups); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#canRemoveRegisterGroups(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + public boolean canRemoveRegisterGroups(IStructuredSelection selection) { + IRegisterGroup[] groups = getRegisterGroups(selection); + if (groups.length > 0) { + return true; + } + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#restoreDefaultGroups(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + public void restoreDefaultGroups(IStructuredSelection selection) { + getDebugTarget(selection).restoreDefaultRegisterGroups(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#canRestoreDefaultGroups(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + public boolean canRestoreDefaultGroups(IStructuredSelection selection) { + ICDebugTarget target = getDebugTarget(selection); + return (target != null) ? target.isSuspended() : false; + } + + private ICDebugTarget getDebugTarget(IStructuredSelection selection) { + + Object element = selection.getFirstElement(); + + if (element instanceof IDebugElement) { + return (ICDebugTarget) ((IDebugElement) element).getDebugTarget().getAdapter(ICDebugTarget.class); + } + return null; + } + + private IPersistableRegisterGroup getRegisterGroup(IStructuredSelection ss) { + IPersistableRegisterGroup selectedGroup = null; + if (!ss.isEmpty()) { + Object s = ss.getFirstElement(); + if (s instanceof IPersistableRegisterGroup) { + selectedGroup = (IPersistableRegisterGroup) s; + } + } + + return selectedGroup; + } + + private IRegisterGroup[] getRegisterGroups(IStructuredSelection ss) { + ArrayList list = new ArrayList(); + for (Iterator iterator = ss.iterator(); iterator.hasNext();) { + Object selection = iterator.next(); + if (selection instanceof IRegisterGroup) { + list.add((IRegisterGroup) selection); + } + } + + return list.toArray(new IRegisterGroup[list.size()]); + } + +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/AddRegisterGroupCommandHandler.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/AddRegisterGroupCommandHandler.java new file mode 100644 index 00000000000..9563d2ad9ad --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/AddRegisterGroupCommandHandler.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.ui.commands; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISources; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Command handler to trigger an AddRegisterGroup operation + */ +public class AddRegisterGroupCommandHandler extends AbstractRegisterGroupCommandHandler { + + public void setEnabled(Object evaluationContext) { + boolean state = false; + if (evaluationContext instanceof IEvaluationContext) { + Object s = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); + if (s instanceof IStructuredSelection) { + state = canAddRegisterGroup((IStructuredSelection)s); + } + } + setBaseEnabled(state); + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (selection instanceof IStructuredSelection) { + addRegisterGroup((IStructuredSelection)selection); + } + return null; + } +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/EditRegisterGroupCommandHandler.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/EditRegisterGroupCommandHandler.java new file mode 100644 index 00000000000..ba376b87e89 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/EditRegisterGroupCommandHandler.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.ui.commands; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISources; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Command handler to trigger an AddRegisterGroup operation + */ +public class EditRegisterGroupCommandHandler extends AbstractRegisterGroupCommandHandler { + + public void setEnabled(Object evaluationContext) { + boolean state = false; + if (evaluationContext instanceof IEvaluationContext) { + Object s = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); + if (s instanceof IStructuredSelection) { + state = canEditRegisterGroup((IStructuredSelection)s); + } + } + setBaseEnabled(state); + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (selection instanceof IStructuredSelection) { + editRegisterGroup((IStructuredSelection)selection); + } + return null; + } +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/RemoveRegisterGroupsCommandHandler.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/RemoveRegisterGroupsCommandHandler.java new file mode 100644 index 00000000000..540c74d6abf --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/RemoveRegisterGroupsCommandHandler.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.ui.commands; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISources; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Command handler to trigger a RemoveRegisterGroups operation + */ +public class RemoveRegisterGroupsCommandHandler extends AbstractRegisterGroupCommandHandler { + + public void setEnabled(Object evaluationContext) { + boolean state = false; + if (evaluationContext instanceof IEvaluationContext) { + Object s = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); + if (s instanceof IStructuredSelection) { + state = canRemoveRegisterGroups((IStructuredSelection)s); + } + } + setBaseEnabled(state); + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (selection instanceof IStructuredSelection) { + removeRegisterGroups((IStructuredSelection)selection); + } + return null; + } +} diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/RestoreRegisterGroupsCommandHandler.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/RestoreRegisterGroupsCommandHandler.java new file mode 100644 index 00000000000..3943cca8401 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/RestoreRegisterGroupsCommandHandler.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.ui.commands; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISources; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Command handler to trigger an AddRegisterGroup operation + */ +public class RestoreRegisterGroupsCommandHandler extends AbstractRegisterGroupCommandHandler { + + public void setEnabled(Object evaluationContext) { + boolean state = false; + if (evaluationContext instanceof IEvaluationContext) { + Object s = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); + if (s instanceof IStructuredSelection) { + state = canRestoreDefaultGroups((IStructuredSelection)s); + } + } + setBaseEnabled(state); + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (selection instanceof IStructuredSelection) { + restoreDefaultGroups((IStructuredSelection)selection); + } + return null; + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBPatternMatchingExpressions.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBPatternMatchingExpressions.java index e83df89332d..74fe922ae22 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBPatternMatchingExpressions.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBPatternMatchingExpressions.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Ericsson and others. + * Copyright (c) 2012, 2014 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 @@ -9,6 +9,7 @@ * Marc Khouzam (Ericsson) - initial API and implementation * Grzegorz Kuligowski - Cannot cast to type that contain commas (bug 393474) * Marc Khouzam (Ericsson) - Support for glob-expressions for local variables (bug 394408) + * Alvaro Sanchez-Leon (Ericsson AB) - Allow user to edit register groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; @@ -37,9 +38,9 @@ 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.IRegisters; import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext; -import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext; +import org.eclipse.cdt.dsf.debug.service.IRegisters2; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.debug.service.IStack; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMContext; @@ -781,41 +782,38 @@ public class GDBPatternMatchingExpressions extends AbstractDsfService implements * @param rm RequestMonitor that will contain the unsorted matches. */ protected void matchRegisters(final IExpressionGroupDMContext globDmc, final DataRequestMonitor> rm) { - final IRegisters registerService = getServicesTracker().getService(IRegisters.class); + final IRegisters2 registerService = getServicesTracker().getService(IRegisters2.class); if (registerService == null) { rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Register service unavailable", null)); //$NON-NLS-1$ return; } - registerService.getRegisterGroups(globDmc, new ImmediateDataRequestMonitor(rm) { - @Override - protected void handleSuccess() { - registerService.getRegisters( - new CompositeDMContext(new IDMContext[] { getData()[0], globDmc } ), - new ImmediateDataRequestMonitor(rm) { - @Override - protected void handleSuccess() { - assert getData() instanceof MIRegisterDMC[]; - ArrayList matches = new ArrayList(); - - String fullExpr = globDmc.getExpression().trim(); - if (fullExpr.startsWith(GLOB_EXPRESSION_PREFIX)) { - // Strip the leading '=' and any extra spaces - fullExpr = fullExpr.substring(1).trim(); - } - - for (MIRegisterDMC register : (MIRegisterDMC[])getData()) { - String potentialMatch = REGISTER_PREFIX + register.getName(); - if (globMatches(fullExpr, potentialMatch)) { - matches.add(createExpression(globDmc, potentialMatch)); - } - } - - rm.done(matches); + final IContainerDMContext contDmc = DMContexts.getAncestorOfType(globDmc, IContainerDMContext.class); + + registerService.getRegisters( + new CompositeDMContext(new IDMContext[] { contDmc, globDmc } ), + new ImmediateDataRequestMonitor(rm) { + @Override + protected void handleSuccess() { + assert getData() instanceof MIRegisterDMC[]; + ArrayList matches = new ArrayList(); + + String fullExpr = globDmc.getExpression().trim(); + if (fullExpr.startsWith(GLOB_EXPRESSION_PREFIX)) { + // Strip the leading '=' and any extra spaces + fullExpr = fullExpr.substring(1).trim(); + } + + for (MIRegisterDMC register : (MIRegisterDMC[])getData()) { + String potentialMatch = REGISTER_PREFIX + register.getName(); + if (globMatches(fullExpr, potentialMatch)) { + matches.add(createExpression(globDmc, potentialMatch)); } - }); - } - }); + } + + rm.done(matches); + } + }); } /** diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisters.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisters.java new file mode 100644 index 00000000000..d9bda88cb36 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisters.java @@ -0,0 +1,1137 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson AB 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: + * Alvaro Sanchez-Leon (Ericsson) - First Implementation and API (Bug 235747) + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; + +import org.eclipse.cdt.debug.core.model.IRegisterDescriptor; +import org.eclipse.cdt.debug.internal.core.RegisterGroupsPersistance; +import org.eclipse.cdt.debug.internal.core.model.IRegisterGroupDescriptor; +import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.CompositeDMContext; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IRegisters; +import org.eclipse.cdt.dsf.debug.service.IRegisters2; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IStack; +import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; +import org.eclipse.cdt.dsf.mi.service.MIRegisters; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.osgi.util.NLS; + +/** + *

An extension of MIRegisters to support management of Register Groups as per the IRegisters2 interface.

+ *

The managed registered groups are user-defined subsets of the complete list of Registers reported by GDB for a specific Target

+ *

This class also triggers the read/write (persistence) of the user-defined Register Groups during the start/shutdown process of a session respectively

+ * @since 4.6 + */ +public class GDBRegisters extends MIRegisters implements IRegisters2 { + + /** + * Unique temporary id for a group. 0 is reserved for the root group + */ + private static int fGroupBookingCount = 1; + + /** + * References to all groups related to a given context. Different programs may use different sets of registers e.g. + * 32/64 bits + */ + private final ContextToGroupsMap fContextToGroupsMap = new ContextToGroupsMap(); + + /** + * Used to save base list of Registers associated to a group, these registers can not be used as is for + * "getRegisters" since the execution context may change e.g. The current selection points to a process or a running + * thread or a different frame, all information besides the execution context is valid. + */ + private final GroupRegistersMap fGroupToRegistersMap = new GroupRegistersMap(); + + /** + * Saves the Group number to RegisterGroupDescriptor created from the serialized memento, The group number is used across contexts as the + * key:Integer uses a booking number incremented across container contexts + */ + private final Map fGroupMementoDescriptorIndex = new HashMap(); + + public GDBRegisters(DsfSession session) { + super(session); + } + + private class ContextToGroupsMap extends HashMap { + private static final long serialVersionUID = 1L; + private final Map> fNameToGroupMap = new HashMap>(); + + @Override + public MIRegisterGroupDMC[] put(IContainerDMContext key, MIRegisterGroupDMC[] value) { + if (key == null || value == null) { + return null; + } + + // Contents are updated for the given context, reset this context + // cache + // So it can be rebuilt on the next get + fNameToGroupMap.remove(key); + return super.put(key, value); + } + + @Override + public void clear() { + fNameToGroupMap.clear(); + fGroupMementoDescriptorIndex.clear(); + fGroupToRegistersMap.clear(); + super.clear(); + } + + @Override + public MIRegisterGroupDMC[] remove(Object key) { + fNameToGroupMap.remove(key); + return super.remove(key); + } + + public Map getGroupNameMap(IContainerDMContext key) { + // validate input + if (key == null) { + return null; + } + + Map nameMap = fNameToGroupMap.get(key); + if (nameMap == null) { + // cache not resolved, rebuild + nameMap = new HashMap(); + MIRegisterGroupDMC[] groupsArr = super.get(key); + // If the container context exist, build the name map + if (groupsArr != null) { + for (MIRegisterGroupDMC group : groupsArr) { + nameMap.put(group.getName(), group); + } + + // cache it ! + fNameToGroupMap.put(key, nameMap); + } + } + + return nameMap; + } + + /** + * Needed when group name(s) change but the associated group objects remain the same + */ + public void resetGroupNameMap(IContainerDMContext key) { + fNameToGroupMap.remove(key); + } + + /** + * The result will reflect the reverse order of creation, i.e. last created first + */ + public MIRegisterGroupDMC[] getReversed(IDMContext key) { + MIRegisterGroupDMC[] groups = get(key); + MIRegisterGroupDMC[] reversedGroups = new MIRegisterGroupDMC[groups.length]; + int size = groups.length; + for (int i = 0; i < size; i++) { + reversedGroups[size - 1 - i] = groups[i]; + } + + return reversedGroups; + } + } + + /** + * Used to associate two dependent maps, Group to ordered Register[] and Group to indexed registers (Map) + */ + private class GroupRegistersMap extends HashMap { + private static final long serialVersionUID = 1L; + private final Map> fNameToRegisterMap = new HashMap>(); + + @Override + public MIRegisterDMC[] put(MIRegisterGroupDMC key, MIRegisterDMC[] value) { + // Make sure a previous entry of the key does not keep an out of + // date cache + fNameToRegisterMap.remove(key); + return super.put(key, value); + } + + public Map getIndexedRegisters(MIRegisterGroupDMC key) { + Map nameToRegisterMap = fNameToRegisterMap.get(key); + if (nameToRegisterMap == null && get(key) != null) { + // Needs indexing + nameToRegisterMap = indexRegisters(key); + if (nameToRegisterMap != null) { + fNameToRegisterMap.put(key, nameToRegisterMap); + } + } + + return nameToRegisterMap; + } + + @Override + public void clear() { + fNameToRegisterMap.clear(); + super.clear(); + } + + @Override + public MIRegisterDMC[] remove(Object key) { + fNameToRegisterMap.remove(key); + return super.remove(key); + } + + private Map indexRegisters(MIRegisterGroupDMC registerGroup) { + MIRegisterDMC[] registers = super.get(registerGroup); + if (registers == null || registers.length < 1) { + return null; + } + + Map registerNameMap = new HashMap(); + for (IRegisterDMContext register : registers) { + assert(register instanceof MIRegisterDMC); + MIRegisterDMC registerDmc = (MIRegisterDMC) register; + registerNameMap.put(registerDmc.getName(), registerDmc); + } + + return registerNameMap; + } + } + + private class RegisterGroupDescriptor implements IRegisterGroupDescriptor { + private final boolean fEnabled; + private final MIRegisterGroupDMC fgroup; + + public RegisterGroupDescriptor(MIRegisterGroupDMC group, boolean enabled) { + fgroup = group; + fEnabled = enabled; + } + + @Override + public String getName() { + return fgroup.getName(); + } + + @Override + public boolean isEnabled() { + return fEnabled; + } + + @Override + public IRegisterDescriptor[] getChildren() throws CoreException { + IRegisterDescriptor[] regDescriptors = null; + // Get a snap shot of the current registers + MIRegisterDMC[] registers = fGroupToRegistersMap.get(fgroup); + if (registers != null && registers.length > 0) { + regDescriptors = new IRegisterDescriptor[registers.length]; + for (int i = 0; i < registers.length; i++) { + regDescriptors[i] = new RegisterDescriptor(registers[i]); + } + } else { + // The registers were probably never fetched, obtain the + // original definitions from deserialized groups + IRegisterGroupDescriptor groupMementoDescriptor = fGroupMementoDescriptorIndex.get(fgroup.getGroupNo()); + if (groupMementoDescriptor != null) { + regDescriptors = groupMementoDescriptor.getChildren(); + } + } + + return regDescriptors; + } + + } + + private class RegisterDescriptor implements IRegisterDescriptor { + private final MIRegisterDMC fRegister; + private final static String ORIGINAL_GROUP_NAME = "Main"; //$NON-NLS-1$ + + public RegisterDescriptor(MIRegisterDMC register) { + fRegister = register; + } + + @Override + public String getName() { + return fRegister.getName(); + } + + @Override + public String getGroupName() { + // Hard coded to keep compatibility with CDI's format + return ORIGINAL_GROUP_NAME; + } + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new ImmediateRequestMonitor(requestMonitor) { + @Override + public void handleSuccess() { + doInitialize(requestMonitor); + }}); + } + + private void doInitialize(final RequestMonitor requestMonitor) { + register(new String[]{IRegisters.class.getName(), + IRegisters2.class.getName(), + MIRegisters.class.getName(), + GDBRegisters.class.getName()}, new Hashtable()); + requestMonitor.done(); + } + + @Override + public void getRegisterGroups(final IDMContext ctx, final DataRequestMonitor rm) { + final IContainerDMContext contDmc = DMContexts.getAncestorOfType(ctx, IContainerDMContext.class); + if (contDmc == null) { + IStatus status = new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, + "Container context not provided, unable to get Register Groups", null); //$NON-NLS-1$ + rm.setStatus(status); + rm.done(); + return; + } + + if (fContextToGroupsMap.containsKey(contDmc)) { + // The groups information is already available and can be returned + rm.setData(fContextToGroupsMap.getReversed(contDmc)); + rm.done(); + return; + } + + // The register groups information needs to be built from GDB and user-defined groups i.e. de-serialized + // from the launch configuration. + super.getRegisterGroups(ctx, new ImmediateDataRequestMonitor(rm) { + @Override + @ConfinedToDsfExecutor("fExecutor") + protected void handleSuccess() { + final IRegisterGroupDMContext[] regGroups = getData(); + // only one group from MI is expected at the moment + assert (regGroups.length == 1); + assert (regGroups[0] instanceof MIRegisterGroupDMC); + + final MIRegisterGroupDMC miGroup = (MIRegisterGroupDMC) regGroups[0]; + + // read serialized groups + MIRegisterGroupDMC[] mementoGroups = readGroupsFromMemento(contDmc); + + // Track the groups associated to this context + // The root group (mi) is placed and expected at index 0 followed + // by the user groups read from the memento + MIRegisterGroupDMC[] regGroupsCtx = concatenateArr(new MIRegisterGroupDMC[] { miGroup }, mementoGroups); + + // Have the information ready for subsequent request or group operations. + fContextToGroupsMap.put(contDmc, regGroupsCtx); + + // Reverse the order i.e. latest on top and get back to parent monitor + rm.setData(fContextToGroupsMap.getReversed(contDmc)); + rm.done(); + } + }); + } + + @Override + public void getRegisterGroupData(final IRegisterGroupDMContext regGroupDmc, + final DataRequestMonitor rm) { + + assert (regGroupDmc instanceof MIRegisterGroupDMC); + + if (regGroupDmc instanceof MIRegisterGroupDMC) { + MIRegisterGroupDMC groupDmc = (MIRegisterGroupDMC) regGroupDmc; + rm.setData(createRegisterGroupData(groupDmc)); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, + "Unable to resolve Group Data, Invalid Register Group provided", null)); //$NON-NLS-1$ + } + + rm.done(); + } + + private IRegisterGroupDMData createRegisterGroupData(final MIRegisterGroupDMC groupDmc) { + + IRegisterGroupDMData groupData = new IRegisterGroupDMData() { + @Override + public String getName() { + return groupDmc.getName(); + } + + @Override + public String getDescription() { + if (groupDmc.getName().equals(ROOT_GROUP_NAME)) { + return ROOT_GROUP_DESCRIPTION; + } + + return BLANK_STRING; + } + + }; + + // Make sure this group is available in the groups to registers map, + // as this map provides the input to save /serialize the groups + // The associated registers will be resolved upon request. + if (fGroupToRegistersMap.get(groupDmc) == null) { + fGroupToRegistersMap.put(groupDmc, new MIRegisterDMC[0]); + } + + return groupData; + } + + @Override + public void getRegisters(final IDMContext aCtx, final DataRequestMonitor rm) { + findRegisterGroup(aCtx, ROOT_GROUP_NAME, new ImmediateDataRequestMonitor() { + @Override + protected void handleSuccess() { + //Get the root group, needed as a possible default group and to resolve target registers + IRegisterGroupDMContext rootGroup = getData(); + assert (rootGroup instanceof MIRegisterGroupDMC); + final MIRegisterGroupDMC rootGroupContext = (MIRegisterGroupDMC) rootGroup; + + //if the received context does not contain a register group i.e.is null, the default group to resolve registers is the root group + MIRegisterGroupDMC tGroupDmc = DMContexts.getAncestorOfType(aCtx, MIRegisterGroupDMC.class); + + IDMContext tCtx = aCtx; + if (tGroupDmc == null) { + tGroupDmc = rootGroupContext; + //We need a register group as part of the context to resolve registers + tCtx = new CompositeDMContext(new IDMContext[] {aCtx, tGroupDmc}); + } + + final IDMContext ctx = tCtx; + + final MIRegisterGroupDMC groupDmc = tGroupDmc; + // check if base registers have been loaded already + MIRegisterDMC[] baseRegisters = fGroupToRegistersMap.get(groupDmc); + if (baseRegisters != null && baseRegisters.length > 0) { + // use baseRegisters to build registers associated to the given context + buildGroupRegisters(ctx, baseRegisters, rm); + return; + } + + IContainerDMContext rootGroupContainer = DMContexts.getAncestorOfType(rootGroupContext, + IContainerDMContext.class); + MIRegisterDMC[] registerBase = fGroupToRegistersMap.get(rootGroupContainer); + if (registerBase == null || registerBase.length < 1) { + // Prepare to fetch the register information from GDB (root group) + // Include the frame/execution context whenever available + IDMContext miExecDmc = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class); + if (miExecDmc == null) { + miExecDmc = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + } + + // if Execution context is not available return shallow registers i.e. no execution context + final CompositeDMContext compCtx; + if (miExecDmc != null) { + compCtx = new CompositeDMContext(new IDMContext[] { rootGroupContext, miExecDmc }); + } else { + compCtx = new CompositeDMContext(new IDMContext[] { rootGroupContext }); + } + + // Fetch the register base from GDB + GDBRegisters.super.getRegisters(compCtx, new DataRequestMonitor(getExecutor(), rm) { + @Override + @ConfinedToDsfExecutor("fExecutor") + protected void handleSuccess() { + IRegisterDMContext[] iregisters = getData(); + MIRegisterDMC[] registers = Arrays.copyOf(iregisters, iregisters.length, MIRegisterDMC[].class); + + // associate group to bare registers i.e. not associated to a specific execution context + fGroupToRegistersMap.put(rootGroupContext, toBareRegisters(registers)); + if (groupDmc.getName().equals(ROOT_GROUP_NAME)) { + buildGroupRegisters(ctx, registers, rm); + return; + } + + // Now proceed to resolve the requested user group registers + getUserGroupRegisters(ctx, rm); + } + }); + } else { + if (groupDmc.getName().equals(ROOT_GROUP_NAME)) { + buildGroupRegisters(ctx, registerBase, rm); + } else { + // resolve user group registers + getUserGroupRegisters(ctx, rm); + } + } + + } + }); + } + + @Override + public void canAddRegisterGroup(IDMContext selectionContext, DataRequestMonitor rm) { + // Not relevant checks at this point + rm.setData(true); + rm.done(); + } + + @Override + public void addRegisterGroup(final IDMContext containerContext, final String groupName, final IRegisterDMContext[] registers, RequestMonitor rm) { + if (registers == null || registers.length < 1) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, + Messages.RegisterGroup_invalid_number_of_registers, null)); + rm.done(); + return; + } + + if (groupName.trim().toLowerCase().equals(ROOT_GROUP_NAME.toLowerCase())) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, + NLS.bind(Messages.RegisterGroup_name_reserved, ROOT_GROUP_NAME), null)); + rm.done(); + return; + } + + if (!(registers[0] instanceof MIRegisterDMC)) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, + "Unexpected IRegisterDMContext input instance type", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + IContainerDMContext contDmc = DMContexts.getAncestorOfType(registers[0], IContainerDMContext.class); + if (contDmc == null) { + contDmc = DMContexts.getAncestorOfType(containerContext, IContainerDMContext.class); + if (contDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, + "Unable to add Register group, Invalid Container", null)); //$NON-NLS-1$ + rm.done(); + return; + } + } + + // must be a child of an existing container, at least the root group must be present + assert (fContextToGroupsMap.containsKey(contDmc)); + + // Make sure the name is not currently in use + if (fContextToGroupsMap.getGroupNameMap(contDmc).get(groupName) != null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, NLS.bind( + Messages.RegisterGroup_name_used, groupName), null)); + rm.done(); + return; + } + + //create the new group + MIRegisterGroupDMC group = new MIRegisterGroupDMC(this, contDmc, fGroupBookingCount, groupName); + fGroupBookingCount++; + + // Update the context to groups map including the new group + fContextToGroupsMap.put(contDmc, + concatenateArr(fContextToGroupsMap.get(contDmc), new MIRegisterGroupDMC[] { group })); + + //type adjustment + MIRegisterDMC[] miRegisters = Arrays.copyOf(registers, registers.length, MIRegisterDMC[].class); + + // associate group to bare registers i.e. not associated to a specific execution context + MIRegisterDMC[] bareRegisters = toBareRegisters(miRegisters); + fGroupToRegistersMap.put(group, bareRegisters); + + // Create event notification, to trigger the UI refresh + getSession().dispatchEvent(new GroupsChangedDMEvent(contDmc), null); + rm.done(); + } + + @Override + public void canEditRegisterGroup(IRegisterGroupDMContext group, DataRequestMonitor rm) { + rm.setData(canEditRegisterGroup(group)); + rm.done(); + } + + @Override + public void editRegisterGroup(IRegisterGroupDMContext group, String newGroupName, IRegisterDMContext[] iRegisters, + RequestMonitor rm) { + + if (iRegisters != null && iRegisters.length == 0) { + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, + Messages.RegisterGroup_invalid_number_of_registers, null)); + return; + } + + if (!(group instanceof MIRegisterGroupDMC)) { + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown DMC type", null)); //$NON-NLS-1$ + return; + } + + IContainerDMContext contDmc = DMContexts.getAncestorOfType(group, IContainerDMContext.class); + if (contDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, + "Unable to edit Register group, Invalid Container", null)); //$NON-NLS-1$ + rm.done(); + } + + MIRegisterGroupDMC miGroup = ((MIRegisterGroupDMC) group); + + if (!canEditRegisterGroup(group)) { + // Should not happen as canEdit is expected to be called before edit + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot currently edit register groups", null)); //$NON-NLS-1$ + return; + } + + if (newGroupName != null && !newGroupName.isEmpty()) { + // Make sure the new group name is not the reserved root group name + if (newGroupName.trim().toLowerCase().equals(ROOT_GROUP_NAME.toLowerCase())) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, + NLS.bind(Messages.RegisterGroup_name_reserved, ROOT_GROUP_NAME), null)); + rm.done(); + return; + } + + // Make sure the name is not currently in use + if (!miGroup.getName().equals(newGroupName)) { + // we are updating the name, lets make sure this new name is not in use + if (fContextToGroupsMap.getGroupNameMap(contDmc).get(newGroupName) != null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, + NLS.bind(Messages.RegisterGroup_name_used, newGroupName), null)); + rm.done(); + return; + } + } + + miGroup.setName(newGroupName); + + //make sure we update the group name cache + fContextToGroupsMap.resetGroupNameMap(contDmc); + + generateRegisterGroupChangedEvent(miGroup); + } else { + // Request to keep name the same + } + + if (iRegisters != null) { + assert (iRegisters.length > 0); + + // transform to MIRegistersDMC[] + MIRegisterDMC[] registers = arrangeRegisters(iRegisters); + + // preserve registers in a general format not associated to a specific frame + registers = toBareRegisters(registers); + fGroupToRegistersMap.put(miGroup, registers); + // Notify of Registers changed + generateRegistersChangedEvent(miGroup); + } else { + // Request to keep register list the same + } + + rm.done(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.cdt.dsf.debug.service.IRegisters2#removeRegisterGroups(org.eclipse.cdt.dsf.debug.service.IRegisters + * .IRegisterGroupDMContext[], org.eclipse.cdt.dsf.concurrent.RequestMonitor) + */ + @Override + public void removeRegisterGroups(IRegisterGroupDMContext[] groups, RequestMonitor rm) { + removeRegisterGroups(groups, false, rm); + } + + @Override + public void restoreDefaultGroups(final IDMContext selectionContext, final RequestMonitor rm) { + for (IDMContext context : fContextToGroupsMap.keySet()) { + removeRegisterGroups(context); + } + + // clean the serialized registers group information + save(); + + // Clear all global references to the contexts and groups + fContextToGroupsMap.clear(); + rm.done(); + } + + /** + * Reset this class i.e. does not impact saved groups within launch configuration + * + * @param rm + */ + public void reset(final RequestMonitor rm) { + for (IDMContext context : fContextToGroupsMap.keySet()) { + removeRegisterGroups(context); + } + + // Clear all global references to the contexts and groups + fContextToGroupsMap.clear(); + rm.done(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.dsf.mi.service.MIRegisters#findRegisterGroup(org.eclipse.cdt.dsf.datamodel.IDMContext, + * java.lang.String, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor) + */ + @Override + public void findRegisterGroup(final IDMContext ctx, final String name, final DataRequestMonitor rm) { + final IContainerDMContext contDmc = DMContexts.getAncestorOfType(ctx, IContainerDMContext.class); + if (contDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, + "Container context not found", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + if (fContextToGroupsMap.get(ctx) == null) { + // Need to build the list of register groups including the one from target + getRegisterGroups(contDmc, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Using the list of groups indirectly to find the one with the given name from it + findRegisterGroup(contDmc, name, rm); + } + }); + } else { + // The context to groups map has been initialized and can be used + findRegisterGroup(contDmc, name, rm); + } + } + + /** + * Call it only after getRegisterGroups has been called at least once, so the context to groups map is not empty + */ + private void findRegisterGroup(IContainerDMContext contDmc, String name, DataRequestMonitor rm) { + Map nameToGroup = fContextToGroupsMap.getGroupNameMap(contDmc); + if (nameToGroup != null) { + rm.setData(nameToGroup.get(name)); + } else { + rm.setData(null); + } + + rm.done(); + } + + @Override + public void shutdown(RequestMonitor rm) { + save(); + super.shutdown(rm); + } + + public void save() { + IRegisterGroupDescriptor[] groups = buildDescriptors(); + ILaunchConfiguration launchConfig = getLaunchConfig(); + if (launchConfig != null) { + RegisterGroupsPersistance serializer = new RegisterGroupsPersistance(launchConfig); + try { + serializer.saveGroups(groups); + } catch (CoreException e1) { + e1.printStackTrace(); + } + } + } + + /** + * Cast to MI and sort them ascending order by register index + */ + private MIRegisterDMC[] arrangeRegisters(IRegisterDMContext[] iRegisters) { + TreeMap sortedRegisters = new TreeMap(); + for (int i = 0; i < iRegisters.length; i++) { + assert(iRegisters[i] instanceof MIRegisterDMC); + MIRegisterDMC register = (MIRegisterDMC) iRegisters[i]; + sortedRegisters.put(register.getRegNo(), register); + } + + return sortedRegisters.values().toArray(new MIRegisterDMC[sortedRegisters.size()]); + } + + /** + * @param groups + * - The groups to be removed + * @param removeRoot + * - indicates if the root group needs to be removed e.g. during restore to defaults + * @param rm + */ + private void removeRegisterGroups(IRegisterGroupDMContext[] groups, boolean removeRoot, RequestMonitor rm) { + if (groups != null) { + // Save a list of updated containers to only send an update event for each of them + final Set updatedContainers = new HashSet(); + for (IRegisterGroupDMContext group : groups) { + + if (!removeRoot) { + // Prevent removal of the Root Group + if (!(group instanceof MIRegisterGroupDMC)) { + // All groups are expected to be instances of MIREgisterGroupDMC + assert (false); + continue; + } + + if (((MIRegisterGroupDMC) group).getName().equals(ROOT_GROUP_NAME)) { + // Skip removal of a root group, except when restoring to default groups + continue; + } + } + + final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(group, IContainerDMContext.class); + + // All given groups are expected to be part of the same Container, however it's safer to create a new list + // per context to cover the unsual case + // This could be revisited in case there is performance concerns which does not seem an issue at this + // point. + MIRegisterGroupDMC[] groupsCtx = fContextToGroupsMap.get(containerDmc); + assert(groupsCtx != null); + + if (groupsCtx != null) { + List groupsList = new ArrayList(Arrays.asList(groupsCtx)); + + // Removing a single group + groupsList.remove(group); + + // Back to context map without the given group + fContextToGroupsMap.put(containerDmc, groupsList.toArray(new MIRegisterGroupDMC[groupsList.size()])); + // Now remove the group from the groups to registers map + if (fGroupToRegistersMap.remove(group) != null) { + updatedContainers.add(containerDmc); + } + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, + "Unable to remove Register group, Invalid Container", null)); //$NON-NLS-1$ + rm.done(); + return; + } + } + + // Sending only one update per container + for (IContainerDMContext container : updatedContainers) { + getSession().dispatchEvent(new GroupsChangedDMEvent(container), null); + } + } + + rm.done(); + } + + private void removeRegisterGroups(IDMContext containerDmc) { + MIRegisterGroupDMC[] groups = fContextToGroupsMap.get(containerDmc); + if (groups != null) { + removeRegisterGroups(groups, true, new RequestMonitor(getExecutor(), null) { + }); + } + } + + private boolean canEditRegisterGroup(IRegisterGroupDMContext group) { + if (group instanceof MIRegisterGroupDMC) { + MIRegisterGroupDMC miGroup = ((MIRegisterGroupDMC) group); + // Prevent changes to the root group + if (miGroup.getName().trim().toLowerCase().equals(ROOT_GROUP_NAME.toLowerCase())) { + return false; + } + + // Expected to be on the existing groups map + if (fGroupToRegistersMap.containsKey(group)) { + return true; + } + } + + return false; + } + + private ILaunchConfiguration getLaunchConfig() { + ILaunch launch = (ILaunch) getSession().getModelAdapter(ILaunch.class); + if (launch == null) { + // The launch is no longer active + return null; + } + + ILaunchConfiguration config = launch.getLaunchConfiguration(); + return config; + } + + private IRegisterGroupDescriptor[] buildDescriptors() { + // use a tree map to sort the entries by group number + TreeMap sortedGroups = new TreeMap(); + + for (MIRegisterGroupDMC group : fGroupToRegistersMap.keySet()) { + sortedGroups.put(Integer.valueOf(group.getGroupNo()), group); + } + + // Not serializing the root group which is dynamically created from GDB + sortedGroups.remove(Integer.valueOf(0)); + + Set> groupSet = sortedGroups.entrySet(); + IRegisterGroupDescriptor[] descriptors = new IRegisterGroupDescriptor[groupSet.size()]; + + // load group descriptors sorted in ascending order to their group + // number into the result array + int i = 0; + for (Iterator> iterator = groupSet.iterator(); iterator.hasNext();) { + Entry entry = iterator.next(); + descriptors[i] = new RegisterGroupDescriptor(entry.getValue(), true); + i++; + } + + return descriptors; + } + + private T[] concatenateArr(T[] origArr, T[] deltaArr) { + if (origArr == null) { + return deltaArr; + } + + if (deltaArr == null) { + return origArr; + } + + T[] newArr = Arrays.copyOf(origArr, origArr.length + deltaArr.length); + System.arraycopy(deltaArr, 0, newArr, origArr.length, deltaArr.length); + return newArr; + } + + private MIRegisterGroupDMC[] readGroupsFromMemento(final IContainerDMContext contDmc) { + RegisterGroupsPersistance deserializer = new RegisterGroupsPersistance(getLaunchConfig()); + IRegisterGroupDescriptor[] groupDescriptions = deserializer.parseGroups(); + + List groups = new ArrayList(); + for (IRegisterGroupDescriptor group : groupDescriptions) { + fGroupMementoDescriptorIndex.put(fGroupBookingCount, group); + groups.add(new MIRegisterGroupDMC(this, contDmc, fGroupBookingCount, group.getName())); + fGroupBookingCount++; + } + + return groups.toArray(new MIRegisterGroupDMC[groups.size()]); + } + + private void getUserGroupRegisters(IDMContext ctx, final DataRequestMonitor rm) { + final MIRegisterGroupDMC groupDmc = DMContexts.getAncestorOfType(ctx, MIRegisterGroupDMC.class); + + // Need to build the corresponding register[] from the memento descriptors + IRegisterGroupDescriptor grpDescriptor = fGroupMementoDescriptorIndex.get(groupDmc.getGroupNo()); + + if (grpDescriptor == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, + "The Register Group Descriptor does not exist for group: " + groupDmc.getName(), null)); //$NON-NLS-1$ + rm.done(); + return; + } + + MIRegisterDMC[] registers; + try { + // Resolve bare registers from the memento descriptors + registers = resolveRegisters(grpDescriptor, ctx); + } catch (CoreException e) { + rm.setStatus(e.getStatus()); + rm.done(); + return; + } + + // update internal data + fGroupToRegistersMap.put(groupDmc, registers); + + // now resolve to context specific registers + buildGroupRegisters(ctx, registers, rm); + } + + /** + * Resolve register dmcs from de-serialized memento descriptors + */ + private MIRegisterDMC[] resolveRegisters(IRegisterGroupDescriptor grpDescriptor, IDMContext ctx) + throws CoreException { + final List registerContexts = new ArrayList(); + final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(ctx, IContainerDMContext.class); + final MIRegisterGroupDMC groupDmc = DMContexts.getAncestorOfType(ctx, MIRegisterGroupDMC.class); + + IRegisterDescriptor[] registerDescriptions = grpDescriptor.getChildren(); + MIRegisterGroupDMC[] groupContexts = fContextToGroupsMap.get(containerDmc); + if (groupContexts != null && groupContexts.length > 0) { + // Get the General Group (base) at index 0, + // Registers map indexed by name + Map indexedRegisterBase = fGroupToRegistersMap.getIndexedRegisters(groupContexts[0]); + + // For each descriptors find its corresponding MIRegisterDMC + for (IRegisterDescriptor registerDescription : registerDescriptions) { + MIRegisterDMC registerDmc = indexedRegisterBase.get(registerDescription.getName()); + if (registerDmc == null) { + // The Register is not present from the base received from GDB + // Create a register DMC with no execution dmc and invalid + // register number e.g. not mapped to a gdb register. + registerDmc = new MIRegisterDMC(this, groupDmc, -1, registerDescription.getName()); + } + + registerContexts.add(registerDmc); + } + } + + return registerContexts.toArray(new MIRegisterDMC[registerContexts.size()]); + } + + @Override + protected void generateRegisterChangedEvent(final IRegisterDMContext dmc) { + // notify the register value change + getSession().dispatchEvent(new RegisterChangedDMEvent(dmc), getProperties()); + + + // Propagate notification to all groups. + // A change of a single register needs to be propagated to all groups within the same Container/Process + // I.e. Some registers are dependent on the value of others and these dependent registers could be + // associated to different groups. + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class); + generateRegistersChangedEvent(containerDmc); + } + + private void generateRegistersChangedEvent(IContainerDMContext containerDmc) { + //resolve the groups for the current container (process) context + final MIRegisterGroupDMC[] groups = fContextToGroupsMap.get(containerDmc); + + //trigger notification to all groups in the container + for (int i = 0; i < groups.length; i++) { + //We need final locals variables from the loop. Use a method call for this + generateRegistersChangedEvent(groups[i]); + } + } + + private void generateRegistersChangedEvent(final MIRegisterGroupDMC groupDmc) { + IRegistersChangedDMEvent event = new IRegistersChangedDMEvent() { + @Override + public IRegisterGroupDMContext getDMContext() { + return groupDmc; + } + }; + + getSession().dispatchEvent(event, getProperties()); + } + + private void generateRegisterGroupChangedEvent(final MIRegisterGroupDMC groupDmc) { + IGroupChangedDMEvent event = new IGroupChangedDMEvent() { + @Override + public IRegisterGroupDMContext getDMContext() { + return groupDmc; + } + }; + + getSession().dispatchEvent(event, getProperties()); + } + + + + /** + * Create Registers from specific execution context to a generic register context, e.g. not associated to a specific + * execution context. + */ + private MIRegisterDMC[] toBareRegisters(MIRegisterDMC[] registers) { + + MIRegisterDMC[] bareRegisters = new MIRegisterDMC[registers.length]; + for (int i = 0; i < registers.length; i++) { + // only one parent i.e. group context + MIRegisterGroupDMC groupDmc = DMContexts.getAncestorOfType(registers[i], MIRegisterGroupDMC.class); + assert (groupDmc != null); + bareRegisters[i] = new MIRegisterDMC(this, groupDmc, registers[i].getRegNo(), registers[i].getName()); + } + + return bareRegisters; + } + + private void buildGroupRegisters(final IDMContext ctx, final MIRegisterDMC[] baseRegisters, + final DataRequestMonitor rm) { + final MIRegisterGroupDMC groupDmc = DMContexts.getAncestorOfType(ctx, MIRegisterGroupDMC.class); + + assert (groupDmc != null); + + final IFrameDMContext frameDmc = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class); + if (frameDmc == null) { + // The selection does not provide a specific frame, then resolve the top frame on the current thread + // if the execution frame is not available proceed with no frame context i.e. will not be able to resolve + // values. + IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + if (execDmc != null) { + IStack stackService = getServicesTracker().getService(IStack.class); + if (stackService != null) { + stackService.getTopFrame(execDmc, new ImmediateDataRequestMonitor(rm) { + @Override + protected void handleSuccess() { + cloneRegistersToContext(groupDmc, getData(), baseRegisters, rm); + } + + @Override + protected void handleFailure() { + // Unable to resolve top frame on current thread. + // The thread could e.g. be in running state, + // we return register instances with no associated execution context + // i.e. unable to resolve its associated value. + cloneRegistersToContext(groupDmc, null, baseRegisters, rm); + } + }); + + return; + } + } + } + + cloneRegistersToContext(groupDmc, frameDmc, baseRegisters, rm); + } + + /** + * Create a new array of register instances with the given context + */ + private void cloneRegistersToContext(MIRegisterGroupDMC groupDmc, IFrameDMContext frameDmc, + MIRegisterDMC[] baseRegisters, DataRequestMonitor rm) { + MIRegisterDMC[] registers = new MIRegisterDMC[baseRegisters.length]; + if (frameDmc != null) { + // build to valid stack frame context + for (int i = 0; i < registers.length; i++) { + registers[i] = new MIRegisterDMC(this, groupDmc, frameDmc, baseRegisters[i].getRegNo(), + baseRegisters[i].getName()); + } + } else { + // build with no execution context, normal case if a selection is pointing to + // e.g. a running thread, a process.. i.e. not able to associate register values. + for (int i = 0; i < registers.length; i++) { + registers[i] = new MIRegisterDMC(this, groupDmc, baseRegisters[i].getRegNo(), + baseRegisters[i].getName()); + } + } + + // return the registers + rm.setData(registers); + rm.done(); + } + + @Override + public void canRemoveRegisterGroups(IRegisterGroupDMContext[] groups, DataRequestMonitor rm) { + if (groups == null || groups.length < 1) { + rm.setData(false); + rm.done(); + return; + } + + for(IRegisterGroupDMContext group : groups) { + assert(group instanceof MIRegisterGroupDMC); + MIRegisterGroupDMC miGroup = (MIRegisterGroupDMC) group; + if (miGroup.getName().equals(ROOT_GROUP_NAME)) { + // Not allowed to remove the root group + rm.setData(false); + rm.done(); + return; + } + } + + rm.setData(true); + rm.done(); + + } + + @Override + public void canRestoreDefaultGroups(IDMContext selectionContext, DataRequestMonitor rm) { + // Not relevant checks at this point + rm.setData(true); + rm.done(); + } + +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java index 6e62fd373bb..924f4cf973c 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java @@ -17,6 +17,7 @@ * William Riley (Renesas) - Support for GDB 7.3 disassembly service (Bug 357270) * Marc Khouzam (Ericsson) - Support for GDB 7.4 processes service (Bug 389945) * Marc Khouzam (Ericsson) - Support dynamic printf in bp service 7.5 (Bug 400628) + * Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; @@ -48,7 +49,6 @@ import org.eclipse.cdt.dsf.mi.service.MIBreakpointsSynchronizer; import org.eclipse.cdt.dsf.mi.service.MIDisassembly; import org.eclipse.cdt.dsf.mi.service.MIExpressions; import org.eclipse.cdt.dsf.mi.service.MIModules; -import org.eclipse.cdt.dsf.mi.service.MIRegisters; import org.eclipse.cdt.dsf.mi.service.MIStack; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.service.DsfSession; @@ -231,7 +231,7 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { @Override protected IRegisters createRegistersService(DsfSession session) { - return new MIRegisters(session); + return new GDBRegisters(session); } @Override diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.java index 13f6e681016..cc3da86b098 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013 Ericsson and others. + * Copyright (c) 2012, 2014 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: * Marc Khouzam (Ericsson) - initial API and implementation + * Alvaro Sanchez-Leon (Ericsson) - Bug 235747 *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; @@ -25,6 +26,9 @@ class Messages extends NLS { public static String UniqueMatch; public static String UniqueMatches; public static String ErrorNotSupported; + public static String RegisterGroup_name_reserved; + public static String RegisterGroup_name_used; + public static String RegisterGroup_invalid_number_of_registers; static { // initialize resource bundle diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.properties index 8a6245c7a19..96bdbce7173 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.properties +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2012 Ericsson and others. +# Copyright (c) 2012, 2014 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: # Marc Khouzam (Ericsson) - initial API and implementation +# Alvaro Sanchez-Leon (Ericsson) - Support Register Groups (Bug 235747) ############################################################################### Tracing_not_supported_error=Tracing not supported @@ -17,3 +18,6 @@ NoMatches=No matches UniqueMatch={0} unique match UniqueMatches={0} unique matches ErrorNotSupported=Operation not supported with this GDB version +RegisterGroup_name_reserved=The group name "{0}" is reserved +RegisterGroup_name_used=The group name "{0}" is already in use +RegisterGroup_invalid_number_of_registers=A minimum of one register is needed for a Register Group diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRegisters.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRegisters.java index e0239b89425..cf7de936f0f 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRegisters.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRegisters.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems and others. + * Copyright (c) 2006, 2014 Wind River Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,6 +11,7 @@ * Roland Grunberg (RedHat) - Refresh all registers once one is changed (Bug 400840) * Alvaro Sanchez-Leon (Ericsson) - Make Registers View specific to a frame (Bug 323552) * Alvaro Sanchez-Leon (Ericsson) - Register view does not refresh register names per process (Bug 418176) + * Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service; @@ -66,7 +67,18 @@ import org.osgi.framework.BundleContext; */ public class MIRegisters extends AbstractDsfService implements IRegisters, ICachingService { - private static final String BLANK_STRING = ""; //$NON-NLS-1$ + /** + * @since 4.6 + */ + protected static final String BLANK_STRING = ""; //$NON-NLS-1$ + /** + * @since 4.6 + */ + protected static final String ROOT_GROUP_NAME = Messages.MIRegisters_General_Registers; + /** + * @since 4.6 + */ + protected static final String ROOT_GROUP_DESCRIPTION = Messages.MIRegisters_General_Registers_description; /* * Support class used to construct Register Group DMCs. */ @@ -83,6 +95,12 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach public int getGroupNo() { return fGroupNo; } public String getName() { return fGroupName; } + /** + * @since 4.6 + */ + public void setName(String groupName) { + fGroupName = groupName; + } @Override public boolean equals(Object other) { @@ -93,7 +111,7 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach @Override public int hashCode() { return super.baseHashCode() ^ fGroupNo; } @Override - public String toString() { return baseToString() + ".group[" + fGroupNo + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + public String toString() { return baseToString() + ".group[" + fGroupNo + "," + fGroupName + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } /* @@ -125,20 +143,20 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach } /** - * This Register context is associated to two parent contexts. A stack frame context (IFrameDMContext), and a register group - * context (MIRegisterGroupDMC). When the scenario requires to build a register contexts from the selection of a thread, then the top - * frame shall be resolved and be provided in this constructor. + * This Register context is associated to two parent contexts. A stack frame context (IFrameDMContext), and a + * register group context (MIRegisterGroupDMC). When the scenario requires to build a register contexts from the + * selection of a thread, then the top frame shall be resolved and be provided in this constructor. * * The frame context is necessary to resolve the register's data e.g. value * * @since 4.3 */ - public MIRegisterDMC(MIRegisters service, MIRegisterGroupDMC group, IFrameDMContext frameDmc, int regNo, String regName) { - super(service.getSession().getId(), - new IDMContext[] { frameDmc, group }); - fRegNo = regNo; - fRegName = regName; - } + public MIRegisterDMC(MIRegisters service, MIRegisterGroupDMC group, IFrameDMContext frameDmc, int regNo, + String regName) { + super(service.getSession().getId(), new IDMContext[] { frameDmc, group }); + fRegNo = regNo; + fRegName = regName; + } public int getRegNo() { return fRegNo; } public String getName() { return fRegName; } @@ -162,7 +180,10 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach private final IRegisterDMContext fRegisterDmc; - RegisterChangedDMEvent(IRegisterDMContext registerDMC) { + /** + * @since 4.6 + */ + public RegisterChangedDMEvent(IRegisterDMContext registerDMC) { fRegisterDmc = registerDMC; } @@ -172,14 +193,33 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach } } + /** + * Indicates a change in the list of Register groups e.g. after addition and removal + * @since 4.6 + */ + public static class GroupsChangedDMEvent implements IRegisters.IGroupsChangedDMEvent { + + private final IContainerDMContext fGroupContainerDmc; + + public GroupsChangedDMEvent(IContainerDMContext containerDMC) { + fGroupContainerDmc = containerDMC; + } + + @Override + public IContainerDMContext getDMContext() { + return fGroupContainerDmc; + } + } + /* * Internal control variables. */ private CommandFactory fCommandFactory; - //One Group per container process + //One Group per container process private final Map fContainerToGroupMap = new HashMap(); + private CommandCache fRegisterNameCache; // Cache for holding the Register Names in the single Group private CommandCache fRegisterValueCache; // Cache for holding the Register Values @@ -267,13 +307,13 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach public void getRegisterGroupData(IRegisterGroupDMContext regGroupDmc, DataRequestMonitor rm) { /** * For the GDB GDBMI implementation there is only on group. The GPR and FPU registers are grouped into - * one set. We are going to hard wire this set as the "General Registers". + * one set. We are going to hard wire this set as the value of ROOT_GROUP_NAME. */ class RegisterGroupData implements IRegisterGroupDMData { @Override - public String getName() { return "General Registers"; } //$NON-NLS-1$ + public String getName() { return ROOT_GROUP_NAME; } @Override - public String getDescription() { return "General Purpose and FPU Register Group"; } //$NON-NLS-1$ + public String getDescription() { return ROOT_GROUP_DESCRIPTION; } } rm.setData( new RegisterGroupData() ) ; @@ -387,7 +427,10 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach }); } - static class RegisterData implements IRegisterDMData { + /** + * @since 4.6 + */ + protected static class RegisterData implements IRegisterDMData { final private String fRegName; final private String fRegDesc; @@ -487,14 +530,18 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach fRegisterValueCache.reset(); } - private void generateRegisterChangedEvent(final IRegisterDMContext dmc ) { + /** + * @since 4.6 + */ + protected void generateRegisterChangedEvent(IRegisterDMContext dmc ) { getSession().dispatchEvent(new RegisterChangedDMEvent(dmc), getProperties()); - // Temporary fix for Bug 400840 + // Fix for Bug 400840 // When one register is modified, it could affect other registers. // To properly reflect that, we send a change for all registers. - // We cheat since we know there is currently only one group. Once we handle - // more groups, this may not work properly. + // We cheat by pretending the group has changed, since we know there is + // only one group. + // This method can be extended by group managers to propagate the event as needed final IRegisterGroupDMContext groupDmc = DMContexts.getAncestorOfType(dmc, IRegisterGroupDMContext.class); if (groupDmc != null) { IRegistersChangedDMEvent event = new IRegistersChangedDMEvent() { @@ -504,8 +551,7 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach } }; getSession().dispatchEvent(event, getProperties()); - } - + } } /* @@ -524,15 +570,16 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach } //Bug 418176 - //Only one group per Process (container) is supported for the time being + //Only one group per Process (container) is supported in the implementation of this class MIRegisterGroupDMC registerGroup = fContainerToGroupMap.get(contDmc); - if (registerGroup == null) { - registerGroup = new MIRegisterGroupDMC( this , contDmc, 0 , "General Registers" ) ; //$NON-NLS-1$ - fContainerToGroupMap.put(contDmc, registerGroup); - } + if (registerGroup == null) { + registerGroup = new MIRegisterGroupDMC(this, contDmc, 0, ROOT_GROUP_NAME); + fContainerToGroupMap.put(contDmc, registerGroup); + } MIRegisterGroupDMC[] groupDMCs = new MIRegisterGroupDMC[] { registerGroup }; + rm.setData(groupDMCs) ; rm.done() ; } @@ -642,48 +689,35 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach * @see org.eclipse.cdt.dsf.debug.service.IRegisters#writeRegister(org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext, java.lang.String, java.lang.String, org.eclipse.cdt.dsf.concurrent.RequestMonitor) */ @Override - public void writeRegister(IRegisterDMContext regCtx, final String regValue, final String formatId, final RequestMonitor rm) { - MIRegisterGroupDMC grpDmc = DMContexts.getAncestorOfType(regCtx, MIRegisterGroupDMC.class); - if ( grpDmc == null ) { - rm.setStatus( new Status( IStatus.ERROR , GdbPlugin.PLUGIN_ID , INVALID_HANDLE , "RegisterGroup context not found" , null ) ) ; //$NON-NLS-1$ - rm.done(); - return; - } - - final MIRegisterDMC regDmc = (MIRegisterDMC)regCtx; - // There is only one group and its number must be 0. - if ( grpDmc.getGroupNo() == 0 ) { - final IExpressions exprService = getServicesTracker().getService(IExpressions.class); - String regName = regDmc.getName(); - final IExpressionDMContext exprCtxt = exprService.createExpression(regCtx, "$" + regName); //$NON-NLS-1$ + public void writeRegister(IRegisterDMContext regCtx, final String regValue, final String formatId, + final RequestMonitor rm) { - final FormattedValueDMContext valueDmc = exprService.getFormattedValueContext(exprCtxt, formatId); - exprService.getFormattedExpressionValue( - valueDmc, - new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - if(! regValue.equals(getData().getFormattedValue()) || ! valueDmc.getFormatID().equals(formatId)){ - exprService.writeExpression(exprCtxt, regValue, formatId, new DataRequestMonitor(getExecutor(), rm) { - @Override - protected void handleSuccess() { - generateRegisterChangedEvent(regDmc); - rm.done(); - } - }); - }//if - else { - rm.done(); - } - }//handleSuccess - } - ); - } - else { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Invalid group = " + grpDmc, null)); //$NON-NLS-1$ - rm.done(); - } - } + assert(regCtx instanceof MIRegisterDMC); + final MIRegisterDMC regDmc = (MIRegisterDMC) regCtx; + + final IExpressions exprService = getServicesTracker().getService(IExpressions.class); + String regName = regDmc.getName(); + final IExpressionDMContext exprCtxt = exprService.createExpression(regCtx, "$" + regName); //$NON-NLS-1$ + + final FormattedValueDMContext valueDmc = exprService.getFormattedValueContext(exprCtxt, formatId); + exprService.getFormattedExpressionValue(valueDmc, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (!regValue.equals(getData().getFormattedValue()) || !valueDmc.getFormatID().equals(formatId)) { + exprService.writeExpression(exprCtxt, regValue, formatId, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + generateRegisterChangedEvent(regDmc); + rm.done(); + } + }); + }// if + else { + rm.done(); + } + }// handleSuccess + }); + } /* * (non-Javadoc) diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java index 2eed408eb77..d7435c8063e 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 Ericsson and others. + * Copyright (c) 2010, 2014 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 @@ -8,6 +8,7 @@ * Contributors: * Ericsson - initial API and implementation * Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121) + * Alvaro Sanchez-Leon (Ericsson) - Support Register Groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service; @@ -23,6 +24,8 @@ class Messages extends NLS { public static String Breakpoint_installation_failed; public static String MIExpressions_NotAvailableBecauseChildOfDynamicVarobj; public static String MIExpressions_ReturnValueAlias; + public static String MIRegisters_General_Registers; + public static String MIRegisters_General_Registers_description; static { // initialize resource bundle diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties index 62306b7f606..ddee09bb77f 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2010 Ericsson and others. +# Copyright (c) 2010, 2014 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 @@ -8,6 +8,7 @@ # Contributors: # Ericsson - initial API and implementation # Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121) +# Alvaro Sanchez-Leon (Ericsson) - Support Register Groups (Bug 235747) ############################################################################### Breakpoint_attribute_detailed_problem=Breakpoint installation failed: {0} @@ -16,3 +17,7 @@ Breakpoint_installation_failed=installation failed MIExpressions_NotAvailableBecauseChildOfDynamicVarobj=N/A (child of pretty-printed object) MIExpressions_ReturnValueAlias=%s returned + +MIRegisters_General_Registers=General Registers + +MIRegisters_General_Registers_description=General Purpose and FPU Register Group diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java index 3acf3646c99..3814137d1c4 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 Ericsson and others. + * Copyright (c) 2007, 2014 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 @@ -9,9 +9,11 @@ * Ericsson - Initial Implementation * Marc Khouzam (Ericsson) - Add support to receive multiple events * Alvaro Sanchez-Leon (Ericsson) - Add filter out and wait for a given type of event + * Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.tests.dsf.gdb.framework; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -96,29 +98,34 @@ public class ServiceEventWaitor { } /** - * Will wait and discard events that are not either of the specified type or a subtype - * It will stop and return the first one found or exit after the specified timeout - * - * @param type - The parent type of an acceptable event - * @param timeout the maximum time to wait in milliseconds to wait for a specified event + * Wait for events of V type for the specified amount of time */ - @SuppressWarnings("unchecked") - public synchronized T waitForEvent(Class type, int timeout) throws Exception { + public synchronized List waitForEvents(int period) { long startMs = System.currentTimeMillis(); - //The Specified Event received or Timeout exception will exit the loop + List events = new ArrayList(); + + //Timeout exception will exit the loop and return the resulting list of events while (true) { - int timeRemaining = (int) (timeout - (System.currentTimeMillis() - startMs)); - if (timeRemaining > 0) { - V sevent = waitForEvent(timeRemaining); - if (type.isAssignableFrom(sevent.getClass())) { - return (T) sevent; - } + int timeRemaining = (int) (period - (System.currentTimeMillis() - startMs)); + if (timeRemaining > 0) { + V sevent; + try { + sevent = waitForEvent(timeRemaining); + if (sevent != null) { + events.add(sevent); + } + } catch (Exception e) { + break; + } } else { - throw new Exception("Timed out waiting for ServiceEvent: " + type.getName()); + break; } } + + return events; } + /* * Block until 'timeout' or the expected event occurs. The expected event is * specified at construction time. diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/GDBPatternMatchingExpressionsTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/GDBPatternMatchingExpressionsTest.java index efb542135a7..38cbd2e6691 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/GDBPatternMatchingExpressionsTest.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/GDBPatternMatchingExpressionsTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Ericsson and others. + * Copyright (c) 2012, 2014 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 @@ -8,6 +8,7 @@ * Contributors: * Marc Khouzam (Ericsson) - Initial Implementation * Marc Khouzam (Ericsson) - Tests for Pattern Matching for variables (Bug 394408) + * Alvaro Sanchez-Leon (Ericsson AB) - Allow user to edit register groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.tests.dsf.gdb.tests; @@ -24,9 +25,7 @@ import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Query; -import org.eclipse.cdt.dsf.datamodel.CompositeDMContext; 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; @@ -36,9 +35,8 @@ import org.eclipse.cdt.dsf.debug.service.IExpressions3.IExpressionDMDataExtensio import org.eclipse.cdt.dsf.debug.service.IFormattedValues; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; -import org.eclipse.cdt.dsf.debug.service.IRegisters; import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext; -import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext; +import org.eclipse.cdt.dsf.debug.service.IRegisters2; import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; @@ -67,7 +65,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseTestCase { private DsfServicesTracker fServicesTracker; protected IMIExpressions fExpService; - protected IRegisters fRegService; + protected IRegisters2 fRegService; @Override protected void setLaunchAttributes() { @@ -88,7 +86,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseTestCase { fExpService = fServicesTracker.getService(IMIExpressions.class); - fRegService = fServicesTracker.getService(IRegisters.class); + fRegService = fServicesTracker.getService(IRegisters2.class); } }; fSession.getExecutor().submit(runnable).get(); @@ -173,33 +171,27 @@ public class GDBPatternMatchingExpressionsTest extends BaseTestCase { Query query = new Query() { @Override protected void execute(final DataRequestMonitor rm) { - fRegService.getRegisterGroups(threadDmc, new ImmediateDataRequestMonitor(rm) { - @Override - protected void handleSuccess() { - fRegService.getRegisters( - new CompositeDMContext(new IDMContext[] { getData()[0], threadDmc } ), - new ImmediateDataRequestMonitor(rm) { - @Override - protected void handleSuccess() { - assert getData() instanceof MIRegisterDMC[]; - for (MIRegisterDMC register : (MIRegisterDMC[])getData()) { - if (register.getName().equals(regName)) { - final FormattedValueDMContext valueDmc = fRegService.getFormattedValueContext(register, IFormattedValues.HEX_FORMAT); - fRegService.getFormattedExpressionValue(valueDmc, new ImmediateDataRequestMonitor(rm) { - @Override - protected void handleSuccess() { - rm.done(getData().getFormattedValue()); - }; - }); - return; - } - } - // If we get here, we didn't find the register! - assertTrue("Invalid register: " + regName, false); + fRegService.getRegisters(threadDmc, + new ImmediateDataRequestMonitor(rm) { + @Override + protected void handleSuccess() { + assert getData() instanceof MIRegisterDMC[]; + for (MIRegisterDMC register : (MIRegisterDMC[])getData()) { + if (register.getName().equals(regName)) { + final FormattedValueDMContext valueDmc = fRegService.getFormattedValueContext(register, IFormattedValues.HEX_FORMAT); + fRegService.getFormattedExpressionValue(valueDmc, new ImmediateDataRequestMonitor(rm) { + @Override + protected void handleSuccess() { + rm.done(getData().getFormattedValue()); + }; + }); + return; } - }); - } - }); + } + // If we get here, we didn't find the register! + assertTrue("Invalid register: " + regName, false); + } + }); } }; diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIRegistersTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIRegistersTest.java index 52730259ba2..2cf5d2d839a 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIRegistersTest.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIRegistersTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2010 Ericsson and others. + * Copyright (c) 2009, 2014 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 @@ -8,61 +8,66 @@ * Contributors: * Ericsson - initial API and implementation * Alvaro Sanchez-Leon (Ericsson) - Make Registers View specific to a frame (Bug 323552) + * Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.tests.dsf.gdb.tests; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; import org.eclipse.cdt.dsf.concurrent.ImmediateCountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.Query; -import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.CompositeDMContext; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IFormattedValues; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; -import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; import org.eclipse.cdt.dsf.debug.service.IRegisters; import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext; import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData; import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext; import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData; +import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegistersChangedDMEvent; +import org.eclipse.cdt.dsf.debug.service.IRegisters2; import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; -import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.gdb.service.GDBRegisters; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; -import org.eclipse.cdt.dsf.mi.service.IMIProcesses; -import org.eclipse.cdt.dsf.mi.service.MIProcesses; import org.eclipse.cdt.dsf.mi.service.MIRegisters.MIRegisterDMC; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterNamesInfo; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; -import org.eclipse.cdt.tests.dsf.gdb.framework.AsyncCompletionWaitor; import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner; import org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase; +import org.eclipse.cdt.tests.dsf.gdb.framework.ServiceEventWaitor; import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil; import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin; import org.junit.Assert; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -73,13 +78,13 @@ public class MIRegistersTest extends BaseTestCase { protected static List fRegisterNames = null; @BeforeClass - public static void initializeGlobals() { + public static void initializeGlobals() { // In case we run multiple GDB versions of this test // in the same suite, we need to re-initialize the registers // as they may change between GDB versions. fRegisterNames = null; } - + protected List get_X86_REGS() throws Throwable { if (fRegisterNames == null) { // The tests must run on different machines, so the set of registers can change. @@ -91,8 +96,8 @@ public class MIRegistersTest extends BaseTestCase { @Override protected void execute(DataRequestMonitor rm) { IMICommandControl controlService = fServicesTracker.getService(IMICommandControl.class); - controlService.queueCommand( - controlService.getCommandFactory().createMIDataListRegisterNames(fContainerDmc), rm); + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(fCompositeDmc, IContainerDMContext.class); + controlService.queueCommand(controlService.getCommandFactory().createMIDataListRegisterNames(containerDmc), rm); } }; fSession.getExecutor().execute(query); @@ -101,7 +106,7 @@ public class MIRegistersTest extends BaseTestCase { String[] names = data.getRegisterNames(); // Remove registers with empty names since the service also - // remove them. I don't know why GDB returns such empty names. + // remove them. I don't know why GDB returns such empty names. fRegisterNames = new LinkedList(); for (String name : names) { if (!name.isEmpty()) { @@ -111,179 +116,174 @@ public class MIRegistersTest extends BaseTestCase { } return fRegisterNames; } - + /* * Path to executable */ private static final String EXEC_PATH = "data/launch/bin/"; + /* * Name of the executable */ private static final String EXEC_NAME = "MultiThread.exe"; private static final String SRC_NAME = "MultiThread.cc"; + private static final String GROUP_X = "GroupX"; + private static final String GROUP_Y = "GroupY"; + private static final String PROPOSE_GROUP_NAME_BASE = "Group_"; + private DsfSession fSession; private DsfServicesTracker fServicesTracker; - private IContainerDMContext fContainerDmc; - private IRegisters fRegService; - private IRunControl fRunControl; + private IDMContext fCompositeDmc; + private IRegisters2 fRegService; + private IRunControl fRunControl; + private Integer fGroupNameSuffix; - @Override + @Override public void doBeforeTest() throws Exception { super.doBeforeTest(); - - fSession = getGDBLaunch().getSession(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - // We obtain the services we need after the new - // launch has been performed - fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); - ICommandControlService commandControl = fServicesTracker.getService(ICommandControlService.class); - IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - IProcessDMContext procDmc = procService.createProcessContext(commandControl.getContext(), MIProcesses.UNIQUE_GROUP_ID); - fContainerDmc = procService.createContainerContext(procDmc, MIProcesses.UNIQUE_GROUP_ID); - - fRegService = fServicesTracker.getService(IRegisters.class); - fRunControl = fServicesTracker.getService(IRunControl.class); - } - }; - fSession.getExecutor().submit(runnable).get(); + fSession = getGDBLaunch().getSession(); + + Runnable runnable = new Runnable() { + @Override + public void run() { + // We obtain the services we need after the new + // launch has been performed + fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); + + fRegService = (IRegisters2) fServicesTracker.getService(IRegisters.class); + fRunControl = fServicesTracker.getService(IRunControl.class); + } + }; + + fSession.getExecutor().submit(runnable).get(); + + //resolve the execution context + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = null; + try { + frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + } catch (Throwable e1) { + e1.printStackTrace(); + fail("Initialization problem"); + } + + //resolve the container context + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(getInitialStoppedEvent().getDMContext(), IContainerDMContext.class); + //The container dmc is expected to contain the frame and container context + fCompositeDmc = new CompositeDMContext(new IDMContext[] { containerDmc, frameDmc }); + fGroupNameSuffix = 0; } @Override protected void setLaunchAttributes() { super.setLaunchAttributes(); - - setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, - EXEC_PATH + EXEC_NAME); + + setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EXEC_PATH + EXEC_NAME); + } - - + + @Override public void doAfterTest() throws Exception { super.doAfterTest(); - + fServicesTracker.dispose(); fRegService = null; } - /* - * This is a common support method which gets the Register Group Information - * and verifies it. - */ - private IRegisterGroupDMContext getRegisterGroup() throws Throwable { - final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); + /* + * This is a common support method which gets the Register Group Information from target + */ + private IRegisterGroupDMContext getTargetRegisterGroup() throws Throwable { + //Get all the registers from the Container (Process) + IRegisterDMContext[] registers = getRegisters(fCompositeDmc); + assertTrue(registers.length > 0); + + //Get the register group from any of the register contexts + IRegisterGroupDMContext regGroupsDMC = DMContexts.getAncestorOfType(registers[0], IRegisterGroupDMContext.class); + assertNotNull(regGroupsDMC); - final DataRequestMonitor regGroupDone = - new DataRequestMonitor(fRegService.getExecutor(), null) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - fWait.setReturnInfo(getData()); - } - - fWait.waitFinished(getStatus()); - } - }; - - fRegService.getExecutor().submit(new Runnable() { - @Override - public void run() { - fRegService.getRegisterGroups(fContainerDmc, regGroupDone); - } - }); - - fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); - assertTrue(fWait.getMessage(), fWait.isOK()); + return regGroupsDMC; + } - IRegisterGroupDMContext[] regGroupsDMCs = (IRegisterGroupDMContext[])fWait.getReturnInfo(); - assertTrue("There was more than one register group (" + regGroupsDMCs.length + ")", //$NON-NLS-1$ - regGroupsDMCs.length == 1 ); - fWait.waitReset(); - - return(regGroupsDMCs[0]); - } + /* + * This is a common support method which gets the Registers names. + */ + private IRegisterDMContext[] getAllRegisters(final IFrameDMContext frameDmc) throws Throwable { + + Query queryRegisters = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.getRegisters(new CompositeDMContext(new IDMContext[] { fCompositeDmc, frameDmc }), rm); + } + }; + + fSession.getExecutor().execute(queryRegisters); + + IRegisterDMContext[] regContexts = queryRegisters.get(500, TimeUnit.MILLISECONDS); + + assertEquals("Wrong number of registers", get_X86_REGS().size(), regContexts.length); + + return regContexts; + } /* - * This is a common support method which gets the Registers names. + * Get the Registers for the specified composite context */ - - private IRegisterDMContext[] getRegisters(final IFrameDMContext frameDmc) throws Throwable { - final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); - final IRegisterGroupDMContext regGroupsDMC = getRegisterGroup(); + private IRegisterDMContext[] getRegisters(final IDMContext dmc) throws Throwable { + + Query queryRegistersDmc = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.getRegisters(dmc, rm); + } + }; - fRegService.getExecutor().submit(new Runnable() { - @Override - public void run() { - fRegService.getRegisters( - new CompositeDMContext(new IDMContext[] { regGroupsDMC, frameDmc} ), - new DataRequestMonitor(fRegService.getExecutor(), null) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - fWait.setReturnInfo(getData()); - } - - fWait.waitFinished(getStatus()); - } - }); - } - }); - - fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); - assertTrue(fWait.getMessage(), fWait.isOK()); - - IRegisterDMContext[] regContexts = (IRegisterDMContext[]) fWait.getReturnInfo(); - - fWait.waitReset(); - - assertEquals("Wrong number of registers", get_X86_REGS().size(), regContexts.length); + fRegService.getExecutor().submit(queryRegistersDmc); + IRegisterDMContext[] regContexts = queryRegistersDmc.get(500, TimeUnit.MILLISECONDS); return(regContexts); } - - /************************************************************************* - * - * The tests for the register service. - * - *************************************************************************/ - - @Test - public void getRegisterGroups() throws Throwable { - final IRegisterGroupDMContext regGroupsDMC = getRegisterGroup(); + + /* + * This is a common support method which gets the Register context of root group over the specified frame context + */ + private IRegisterDMContext[] getTargetRegisters(final IFrameDMContext frameDmc) throws Throwable { + IRegisterDMContext[] regContexts = getRegisters(new CompositeDMContext(new IDMContext[] { fCompositeDmc, frameDmc})); + assertEquals("Wrong number of registers", get_X86_REGS().size(), regContexts.length); - Query query = new Query() { - @Override - protected void execute(DataRequestMonitor rm) { - fRegService.getRegisterGroupData(regGroupsDMC, rm); - } - }; - fSession.getExecutor().execute(query); - - IRegisterGroupDMData data = query.get(); - - assertTrue("The name of the main group should be: General Registers instead of: " + - data.getName(), - data.getName().equals("General Registers")); + return regContexts; } - - @Test - public void getRegistersLength() throws Throwable { - MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); - IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); - final IRegisterDMContext[] regDMCs = getRegisters(frameDmc); - assertEquals("Wrong number of registers", get_X86_REGS().size(), regDMCs.length); - } - - @Test - public void getRegisters() throws Throwable { - MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); - IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); - final IRegisterDMContext[] regDMCs = getRegisters(frameDmc); - List regNames = get_X86_REGS(); + + /************************************************************************* + * + * The tests for the register service. + * + *************************************************************************/ + @Test + public void resolveTargetRegisterGroup() throws Throwable { + final IRegisterGroupDMContext regGroupsDMC = getTargetRegisterGroup(); + IRegisterGroupDMData data = getRegisterGroupData(regGroupsDMC); + + assertTrue("The name of the main group should be: General Registers instead of: " + data.getName(), data.getName().equals("General Registers")); + } + + @Test + public void resolveTargetRegistersLength() throws Throwable { + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); + assertEquals("Wrong number of registers", get_X86_REGS().size(), regDMCs.length); + } + + @Test + public void getRegisters() throws Throwable { + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); + List regNames = get_X86_REGS(); IRegisterDMData[] datas = getRegistersData(regDMCs); @@ -295,113 +295,99 @@ public class MIRegistersTest extends BaseTestCase { private IRegisterDMData[] getRegistersData(final IRegisterDMContext[] regDMCs) throws InterruptedException, ExecutionException { - Query query = new Query() { - @Override - protected void execute(DataRequestMonitor rm) { - final IRegisterDMData[] datas = new IRegisterDMData[regDMCs.length]; - rm.setData(datas); - final CountingRequestMonitor countingRm = new ImmediateCountingRequestMonitor(rm); - countingRm.setDoneCount(regDMCs.length); - for (int i = 0; i < regDMCs.length; i++) { - final int index = i; - fRegService.getRegisterData( - regDMCs[index], - new ImmediateDataRequestMonitor(countingRm) { - @Override - protected void handleSuccess() { - datas[index] = getData(); - countingRm.done(); - } - }); - } - - } - }; + Query query = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + final IRegisterDMData[] datas = new IRegisterDMData[regDMCs.length]; + rm.setData(datas); + final CountingRequestMonitor countingRm = new ImmediateCountingRequestMonitor(rm); + countingRm.setDoneCount(regDMCs.length); + for (int i = 0; i < regDMCs.length; i++) { + final int index = i; + fRegService.getRegisterData(regDMCs[index], new ImmediateDataRequestMonitor(countingRm) { + @Override + protected void handleSuccess() { + datas[index] = getData(); + countingRm.done(); + } + }); + } + + } + }; + + fSession.getExecutor().execute(query); - fSession.getExecutor().execute(query); - return query.get(); } private String getModelDataForRegisterDataValue(IFrameDMContext frameDmc, String format, int regNo) throws Throwable { - final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); - - final IRegisterDMContext[] regDMCs = getRegisters(frameDmc); - final FormattedValueDMContext valueDmc = fRegService.getFormattedValueContext(regDMCs[regNo], format); - - final DataRequestMonitor regRm = - new DataRequestMonitor(fRegService.getExecutor(), null) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - wait.setReturnInfo(getData()); - } - - wait.waitFinished(getStatus()); - } - }; - - fRegService.getExecutor().submit(new Runnable() { - @Override - public void run() { - fRegService.getFormattedExpressionValue(valueDmc, regRm); - } - }); - - wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); - assertTrue(wait.getMessage(), wait.isOK()); + final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); + return getModelDataForRegisterDataValue(regDMCs[regNo], format); + } - - FormattedValueDMData data = (FormattedValueDMData)wait.getReturnInfo(); - return data.getFormattedValue(); - } + private String getModelDataForRegisterDataValue(IRegisterDMContext registerDmc, String format) throws Throwable { + + final FormattedValueDMContext valueDmc = fRegService.getFormattedValueContext(registerDmc, format); + + Query queryFormattedData = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.getFormattedExpressionValue(valueDmc, rm); + } + }; + + fRegService.getExecutor().submit(queryFormattedData); + + FormattedValueDMData data = queryFormattedData.get(500, TimeUnit.MILLISECONDS); + return data.getFormattedValue(); + } - @Test - public void getModelDataForRegisterDataValueInDifferentNumberFormats() throws Throwable { - MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); - IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); - String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0); - try { - Long.parseLong(val); - } catch (NumberFormatException e) { - assertTrue("Register Value is not in NATURAL_FORMAT: " + val, false); - } + @Test + public void getModelDataForRegisterDataValueInDifferentNumberFormats() throws Throwable { + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0); + try { + Long.parseLong(val); + } catch (NumberFormatException e) { + assertTrue("Register Value is not in NATURAL_FORMAT: " + val, false); + } - val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, 0); - assertTrue("Register Value is not in HEX_FORMAT: " + val, val.startsWith("0x")); - try { - Long.parseLong(val.substring(2), 16); - } catch (NumberFormatException e) { - assertTrue("Register Value is not in HEX_FORMAT: " + val, false); - } + val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, 0); + assertTrue("Register Value is not in HEX_FORMAT: " + val, val.startsWith("0x")); + try { + Long.parseLong(val.substring(2), 16); + } catch (NumberFormatException e) { + assertTrue("Register Value is not in HEX_FORMAT: " + val, false); + } - val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, 0); - try { - Long.parseLong(val, 2); - } catch (NumberFormatException e) { - assertTrue("Register Value is not in BINARY_FORMAT: " + val, false); - } + val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, 0); + try { + Long.parseLong(val, 2); + } catch (NumberFormatException e) { + assertTrue("Register Value is not in BINARY_FORMAT: " + val, false); + } - val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.DECIMAL_FORMAT , 0); - try { - Long.parseLong(val); - } catch (NumberFormatException e) { - assertTrue("Register Value is not in DECIMAL_FORMAT: " + val, false); - } + val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.DECIMAL_FORMAT, 0); + try { + Long.parseLong(val); + } catch (NumberFormatException e) { + assertTrue("Register Value is not in DECIMAL_FORMAT: " + val, false); + } - val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, 0); - assertTrue("Register Value is not in OCTAL_FORMAT: " + val, val.startsWith("0")); - try { - Long.parseLong(val.substring(1), 8); - } catch (NumberFormatException e) { - assertTrue("Register Value is not in OCTAL_FORMAT: " + val, false); - } - } - - @Test - public void compareRegisterForMultipleExecutionContexts() throws Throwable { + val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, 0); + assertTrue("Register Value is not in OCTAL_FORMAT: " + val, val.startsWith("0")); + try { + Long.parseLong(val.substring(1), 8); + } catch (NumberFormatException e) { + assertTrue("Register Value is not in OCTAL_FORMAT: " + val, false); + } + } + @Test + public void compareRegisterForMultipleExecutionContexts() throws Throwable { // Run past the line that creates a thread and past the sleep that // follows it. This is a bit tricky because the code that creates the // thread is conditional depending on environment. Run to the printf @@ -409,161 +395,151 @@ public class MIRegistersTest extends BaseTestCase { // non-common code (but same number of lines) SyncUtil.runToLine(SRC_NAME, MIRunControlTest.LINE_MAIN_PRINTF); - // Because the program is about to go multi-threaded, we have to select the thread - // we want to keep stepping. If we don't, we will ask GDB to step the entire process - // which is not what we want. We can fetch the thread from the stopped event - // but we should do that before the second thread is created, to be sure the stopped - // event is for the main thread. - MIStoppedEvent stoppedEvent = SyncUtil.step(StepType.STEP_OVER); // over the printf - SyncUtil.step(stoppedEvent.getDMContext(), StepType.STEP_OVER); // over the create-thread call - stoppedEvent = SyncUtil.step(stoppedEvent.getDMContext(), StepType.STEP_OVER, TestsPlugin.massageTimeout(2000)); // over the one second sleep - - // Get the thread IDs - final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(stoppedEvent.getDMContext(), IContainerDMContext.class); - - final AsyncCompletionWaitor wait = new AsyncCompletionWaitor(); - final DataRequestMonitor drm = - new DataRequestMonitor(fRegService.getExecutor(), null) { - @Override - protected void handleCompleted() { - if (isSuccess()) { - wait.setReturnInfo(getData()); - } - wait.waitFinished(getStatus()); - } - }; - - fRegService.getExecutor().submit(new Runnable() { - @Override - public void run() { - fRunControl.getExecutionContexts(containerDmc, drm); - } - }); - wait.waitUntilDone(TestsPlugin.massageTimeout(5000)); - Assert.assertTrue(wait.getMessage(), wait.isOK()); + // Because the program is about to go multi-threaded, we have to select the thread we want to keep stepping. If we don't, we will ask GDB to step + // the entire process which is not what we want. We can fetch the thread from the stopped event but we should do that before the second thread is + // created, to be sure the stopped event is for the main thread. + MIStoppedEvent stoppedEvent = SyncUtil.step(StepType.STEP_OVER); // over the printf + SyncUtil.step(stoppedEvent.getDMContext(), StepType.STEP_OVER); // over the create-thread call + stoppedEvent = SyncUtil.step(stoppedEvent.getDMContext(), StepType.STEP_OVER, TestsPlugin.massageTimeout(2000)); // over the one second sleep - IExecutionDMContext[] ctxts = (IExecutionDMContext[])wait.getReturnInfo(); - wait.waitReset(); + // Get the thread IDs + final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(stoppedEvent.getDMContext(), IContainerDMContext.class); + + Query queryExecutionContexts = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRunControl.getExecutionContexts(containerDmc, rm); + } + }; + + fRegService.getExecutor().submit(queryExecutionContexts); + + IExecutionDMContext[] ctxts = queryExecutionContexts.get(500, TimeUnit.MILLISECONDS); Assert.assertNotNull(ctxts); Assert.assertTrue(ctxts.length > 1); - - int tid1 = ((IMIExecutionDMContext)ctxts[0]).getThreadId(); - int tid2 = ((IMIExecutionDMContext)ctxts[1]).getThreadId(); - - // Get execution context to thread 2 - IExecutionDMContext execDmc = SyncUtil.createExecutionContext(containerDmc, tid2); - IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(execDmc, 0); - - String thread2RegVal0 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 0); - String thread2RegVal1 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 1); - String thread2RegVal2 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 2); - String thread2RegVal3 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 3); - String thread2RegVal4 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 4); - String thread2RegVal5 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 5); - // Get execution context to thread 1 - execDmc = SyncUtil.createExecutionContext(containerDmc, tid1); - IFrameDMContext frameDmc1 = SyncUtil.getStackFrame(execDmc, 0); - getModelDataForRegisterDataValue(frameDmc1, IFormattedValues.NATURAL_FORMAT, 0); + int tid1 = ((IMIExecutionDMContext) ctxts[0]).getThreadId(); + int tid2 = ((IMIExecutionDMContext) ctxts[1]).getThreadId(); - // Re-set the execution context to 2 and Fetch from the Cache - String dupliThread2RegVal0 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 0); - String dupliThread2RegVal1 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 1); - String dupliThread2RegVal2 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 2); - String dupliThread2RegVal3 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 3); - String dupliThread2RegVal4 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 4); - String dupliThread2RegVal5= getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 5); + // Get execution context to thread 2 + IExecutionDMContext execDmc = SyncUtil.createExecutionContext(containerDmc, tid2); + IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(execDmc, 0); - // If Values not equal , then context haven't been re-set properly - assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal0.equals(dupliThread2RegVal0)); - assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal1.equals(dupliThread2RegVal1)); - assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal2.equals(dupliThread2RegVal2)); - assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal3.equals(dupliThread2RegVal3)); - assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal4.equals(dupliThread2RegVal4)); - assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal5.equals(dupliThread2RegVal5)); - - } - - private void writeRegister(IFrameDMContext frameDmc, final int regIndex, final String regValue, final String formatId) throws Throwable { - final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor(); - - final IRegisterDMContext[] regDMCs = getRegisters(frameDmc); + String thread2RegVal0 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 0); + String thread2RegVal1 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 1); + String thread2RegVal2 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 2); + String thread2RegVal3 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 3); + String thread2RegVal4 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 4); + String thread2RegVal5 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 5); - fRegService.getExecutor().submit(new Runnable() { + // Get execution context to thread 1 + execDmc = SyncUtil.createExecutionContext(containerDmc, tid1); + IFrameDMContext frameDmc1 = SyncUtil.getStackFrame(execDmc, 0); + + getModelDataForRegisterDataValue(frameDmc1, IFormattedValues.NATURAL_FORMAT, 0); + + // Re-set the execution context to 2 and Fetch from the Cache + String dupliThread2RegVal0 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 0); + String dupliThread2RegVal1 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 1); + String dupliThread2RegVal2 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 2); + String dupliThread2RegVal3 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 3); + String dupliThread2RegVal4 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 4); + String dupliThread2RegVal5 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 5); + + // If Values not equal , then context haven't been re-set properly + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal0.equals(dupliThread2RegVal0)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal1.equals(dupliThread2RegVal1)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal2.equals(dupliThread2RegVal2)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal3.equals(dupliThread2RegVal3)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal4.equals(dupliThread2RegVal4)); + assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal5.equals(dupliThread2RegVal5)); + + } + + private void writeRegister(IFrameDMContext frameDmc, final int regIndex, final String regValue, final String formatId) throws Throwable { + final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); + writeRegister(regDMCs[regIndex], regValue, formatId); + } + + private void writeRegister(final IRegisterDMContext registerDmc, final String regValue, final String formatId) throws Throwable { + + Query queryAction = new Query() { @Override - public void run() { - fRegService.writeRegister( - regDMCs[regIndex], - regValue, formatId, - new RequestMonitor(fRegService.getExecutor(), null) { - @Override - protected void handleCompleted() { - fWait.waitFinished(getStatus()); - } - }); - + protected void execute(DataRequestMonitor rm) { + fRegService.writeRegister(registerDmc, regValue, formatId, rm); } - }); + }; - fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); - fWait.waitReset(); - } - + fRegService.getExecutor().submit(queryAction); + queryAction.get(500, TimeUnit.MILLISECONDS); + } + + /** + * Waits for IRegistersChangedDMEvent(s) during a time interval, collects them and returns them after timeout + */ + private List writeRegisterWaitNotication(final IRegisterDMContext registerDmc, final String regValue, final String formatId) + throws Throwable { + ServiceEventWaitor eventWaitor = + new ServiceEventWaitor(fSession, IRegistersChangedDMEvent.class); - @Test - public void writeRegisterNaturalFormat() throws Throwable{ - MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); - IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); - String regValue = "10"; - int regIndex = 3; - writeRegister(frameDmc, 3, regValue, IFormattedValues.NATURAL_FORMAT); - String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, regIndex); - assertTrue("Failed writing register. New value should have been " + regValue, regValue.equals(val)); - } - - @Test - public void writeRegisterHEXFormat() throws Throwable{ - MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); - IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); - String regValue = "0x10"; - int regIndex = 3; - writeRegister(frameDmc, 3, regValue, IFormattedValues.HEX_FORMAT); - String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, regIndex); - assertTrue("Failed writing register. New value should have been " + regValue, regValue.equals(val)); - } - - @Test - @Ignore - public void writeRegisterBinaryFormat() throws Throwable{ - MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); - IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); - //String regValue = "0100101001"; - String regValue = "10"; - int regIndex = 3; - writeRegister(frameDmc, 3, regValue, IFormattedValues.BINARY_FORMAT); - String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, regIndex); - assertTrue("Failed writing register. New value should have been " + regValue + " instead of " + val, regValue.equals(val)); - } + writeRegister(registerDmc, regValue, formatId); + + return eventWaitor.waitForEvents(TestsPlugin.massageTimeout(3000)); + } + + + @Test + public void writeRegisterNaturalFormat() throws Throwable { + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + String regValue = "10"; + int regIndex = 3; + writeRegister(frameDmc, 3, regValue, IFormattedValues.NATURAL_FORMAT); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, regIndex); + assertTrue("Failed writing register. New value should have been " + regValue, regValue.equals(val)); + } + + @Test + public void writeRegisterHEXFormat() throws Throwable { + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + String regValue = "0x10"; + int regIndex = 3; + writeRegister(frameDmc, 3, regValue, IFormattedValues.HEX_FORMAT); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, regIndex); + assertTrue("Failed writing register. New value should have been " + regValue, regValue.equals(val)); + } + + @Test + public void writeRegisterBinaryFormat() throws Throwable { + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + String regValue = "100101001"; + int regIndex = 3; + writeRegister(frameDmc, 3, regValue, IFormattedValues.BINARY_FORMAT); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, regIndex); + assertTrue("Failed writing register. New value should have been " + regValue + " instead of " + val, regValue.equals(val)); + } + + @Test + public void writeRegisterOctalFormat() throws Throwable { + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + // String regValue = "10"; + String regValue = "012"; + int regIndex = 3; + writeRegister(frameDmc, 3, regValue, IFormattedValues.OCTAL_FORMAT); + String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, regIndex); + assertTrue("Failed writing register. New value should have been " + regValue + "instead of " + val, regValue.equals(val)); + } - @Test - public void writeRegisterOctalFormat() throws Throwable{ - MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); - IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); - //String regValue = "10"; - String regValue = "012"; - int regIndex = 3; - writeRegister(frameDmc, 3, regValue, IFormattedValues.OCTAL_FORMAT); - String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, regIndex); - assertTrue("Failed writing register. New value should have been " + regValue + "instead of " + val, regValue.equals(val)); - } - /** * This test validates retrieval of different values for the same register used on different frames */ @Test public void frameSpecificValues() throws Throwable { - // Step to a multi-level stack level to be able to test different stack frames + // Step to a multi-level stack to be able to test different stack frames SyncUtil.runToLocation("PrintHello"); MIStoppedEvent stoppedEvent = SyncUtil.step(StepType.STEP_OVER); int depth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); @@ -577,14 +553,14 @@ public class MIRegistersTest extends BaseTestCase { // Get the stack pointer value for frame0 IFrameDMContext frame0 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); - IRegisterDMContext[] registers_f0 = getRegisters(frame0); + IRegisterDMContext[] registers_f0 = getTargetRegisters(frame0); MIRegisterDMC sp_reg_f0 = (MIRegisterDMC) findStackPointerRegister(sp_name, registers_f0); assertNotNull(sp_reg_f0); String sp_f0_str = getModelDataForRegisterDataValue(frame0, IFormattedValues.HEX_FORMAT, sp_reg_f0.getRegNo()); // Get the stack pointer value for frame1 IFrameDMContext frame1 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1); - IRegisterDMContext[] registers_f1 = getRegisters(frame1); + IRegisterDMContext[] registers_f1 = getTargetRegisters(frame1); MIRegisterDMC sp_reg_f1 = (MIRegisterDMC) findStackPointerRegister(sp_name, registers_f1); assertNotNull(sp_reg_f1); String sp_f1_str = getModelDataForRegisterDataValue(frame1, IFormattedValues.HEX_FORMAT, sp_reg_f1.getRegNo()); @@ -629,4 +605,760 @@ public class MIRegistersTest extends BaseTestCase { return null; } + + @Test + public void getRegisterGroupsData() throws Throwable { + int grpsIncrement = 3; + + //Group name to Group description + Map groupNameToDescMap = new HashMap<>(); + groupNameToDescMap.put("Group_1", ""); + groupNameToDescMap.put("Group_2", ""); + groupNameToDescMap.put("Group_3", ""); + groupNameToDescMap.put("General Registers", "General Purpose and FPU Register Group"); + + //Tracking groups found + Set groupsFound = new HashSet<>(); + + addRegisterGroups(grpsIncrement); + final IRegisterDMContext[] regInGroup = getRegisters(0, 4); + + IRegisterGroupDMData[] groupsData = getRegisterGroupsData(regInGroup[0]); + //increment + root + assertTrue(groupsData.length == grpsIncrement + 1); + for (IRegisterGroupDMData grpData: groupsData) { + // Validate group name + assertTrue(groupNameToDescMap.containsKey(grpData.getName())); + String grpDataDesc = grpData.getDescription(); + String expectedName = groupNameToDescMap.get(grpData.getName()); + + //Validate group description + assertTrue(grpDataDesc.equals(expectedName)); + groupsFound.add(grpData.getName()); + } + + //Make sure all expected groups were found + assertTrue(groupsFound.size() == groupNameToDescMap.size()); + } + + @Test + public void canAddRegisterGroup() throws Throwable { + // only root group expected + final IRegisterGroupDMContext[] groups = getRegisterGroups(1); + assertTrue("Unexpected groups present, only root was expected", groups.length == 1); + assertTrue("Can not Add register groups", canAddRegisterGroup(groups[0])); + } + + @Test + public void canNotEditRootRegisterGroup() throws Throwable { + // only root group expected + final IRegisterGroupDMContext[] groups = getRegisterGroups(1); + assertTrue("Unexpected groups present, only root was expected", groups.length == 1); + + assertFalse("Not expected to allow the editing of the root register group", canEditRegisterGroup(groups[0])); + } + + @Test + public void canNotEditUnknownRegisterGroup() throws Throwable { + // only root group expected + final IRegisterGroupDMContext group = new IRegisterGroupDMContext() { + + @Override + public String getSessionId() { + return "session"; + } + + @Override + public IDMContext[] getParents() { + return new IDMContext[0]; + } + + @Override + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + return null; + } + }; + + assertFalse("Not expected to allow editing of a non registered group", canEditRegisterGroup(group)); + } + + @Test + public void canEditRegisterGroup() throws Throwable { + // only root group expected + final IRegisterGroupDMContext[] groups = getRegisterGroups(1); + assertTrue("Unexpected groups present, only root was expected", groups.length == 1); + + IRegisterGroupDMContext group = addDefaultUserGroup(); + assertTrue("Was not allowed to edit register group", canEditRegisterGroup(group)); + } + + /** + * @throws Throwable + */ + @Test + public void addRegisterGroups() throws Throwable { + // Define a subset of registers to create a register group (from, to) + final IRegisterDMContext[] regInGroup = getRegisters(0, 4); + + // Adding three groups with default names + String groupName = proposeGroupName(); + addGroup(groupName, regInGroup); + // Resolve the new group's sequence number from the pattern "Group_sequenceN" + int starting_sequence = resolveGroupNameSequence(groupName); + + groupName = proposeGroupName(); + addGroup(groupName, regInGroup); + + groupName = proposeGroupName(); + addGroup(groupName, regInGroup); + + // Retrieve the existing groups, expected and validated to root + 3 + IRegisterGroupDMContext[] groups = getRegisterGroups(4); + + // The groups are returned in reversed order to present latest created + // first i.e. index 0 + // The newest group shall be at the top then i.e. 0 + + //Add a valid execution context to resolve the register values + IFrameDMContext frameDmc = DMContexts.getAncestorOfType(regInGroup[0], IFrameDMContext.class); + CompositeDMContext compositeDmc = new CompositeDMContext(new IDMContext[]{frameDmc, groups[0]}); + IRegisterDMContext[] readRegisters = getRegisters(compositeDmc); + + // Same order, same data and same values are expected, although different instances to different parents + assertTrue(sameData(regInGroup, readRegisters, false)); + + // Assert the last created group name + IRegisterGroupDMData groupData = getRegisterGroupData(groups[0]); + // 2 additional groups after creation of the base group in this test case + assertEquals("Group_" + (starting_sequence + 2), groupData.getName()); + } + + @Test + public void editRegisterGroup() throws Throwable { + // Get Register Groups + IRegisterGroupDMContext[] groups = getRegisterGroups(1); + assertEquals("unexpected groups present", 1, groups.length); + + IRegisterGroupDMContext group = addDefaultUserGroup(); + + IRegisterDMContext[] origRegisters = getRegisters(group); + + // Assert the default group name + IRegisterGroupDMData groupData = getRegisterGroupData(group); + assertEquals(GROUP_X, groupData.getName()); + + // Registers to associate to exiting default group + IRegisterDMContext[] newRegisters = getRegisters(5, 9); + + // A different set of registers being assigned to the group + assertFalse((sameData(origRegisters, newRegisters, false))); + + // Modify the name and associated registers of the default group + editGroup(group, GROUP_Y, newRegisters); + + groupData = getRegisterGroupData(group); + assertEquals(GROUP_Y, groupData.getName()); + + IFrameDMContext frameDmc = DMContexts.getAncestorOfType(newRegisters[0], IFrameDMContext.class); + + //Read the context with a valid execution context + CompositeDMContext compositeDmc = new CompositeDMContext(new IDMContext[]{group, frameDmc}); + IRegisterDMContext[] readRegisters = getRegisters(compositeDmc); + + //Same data but not from the same parent group, newRegisters from root, readRegisters from GroupY + assertTrue(sameData(newRegisters, readRegisters, false)); + + } + + @Test + public void canRemoveRegisterGroup() throws Throwable { + // only root group expected + IRegisterGroupDMContext[] groups = getRegisterGroups(1); + assertFalse("Removal of root register group shall not be allowed", canRemoveRegisterGroups(groups)); + + //Add another two groups + // Define a subset of registers to create a register group (from, to) + final IRegisterDMContext[] regInGroup = getRegisters(0, 4); + + // Adding three groups with default names + String groupName = proposeGroupName(); + addGroup(groupName, regInGroup); + + groupName = proposeGroupName(); + addGroup(groupName, regInGroup); + + groupName = proposeGroupName(); + addGroup(groupName, regInGroup); + + // Retrieve the existing groups, expected and validated to root + 3 + groups = getRegisterGroups(4); + + //Remove the root group from the list, so the remaining can be validated + //as can be removed + groups = Arrays.copyOfRange(groups, 0, groups.length-1); + assertTrue("Not allowing removal of groups", canRemoveRegisterGroups(groups)); + + //remove the non root groups and validate the result + removeGroups(groups); + groups = getRegisterGroups(1); + } + + @Test + public void removeRegisterGroups() throws Throwable { + int grpsIncrement = 3; + addRegisterGroups(grpsIncrement); + + // Retrieve the existing groups, expected and validated to 1 root + 3 + IRegisterGroupDMContext[] groups = getRegisterGroups(1 + grpsIncrement); + + // remove one and assert the new size + IRegisterGroupDMContext[] remGroups = new IRegisterGroupDMContext[] { groups[0] }; + removeGroups(remGroups); + getRegisterGroups(grpsIncrement); // assert this to root + 2 + + // remove two more and assert the new size + remGroups = new IRegisterGroupDMContext[] { groups[1], groups[2] }; + removeGroups(remGroups); + getRegisterGroups(1); // assert this to only one i.e. root + + // attempt to remove root -- Shall not be allowed + remGroups = new IRegisterGroupDMContext[] { groups[3] }; + removeGroups(remGroups); + getRegisterGroups(1); // assert this to only one i.e. root + } + + /** + * The root group shall not be deleted i.e. ignore and preserved + */ + @Test + public void removeRegisterGroupsWithRoot() throws Throwable { + int grpsIncrement = 3; + addRegisterGroups(grpsIncrement); + + // Retrieve the existing groups, expected and validated to 1 root + 3 + IRegisterGroupDMContext[] groups = getRegisterGroups(1 + grpsIncrement); + + // Attempt to remove all i.e. root + user defined register groups + removeGroups(groups); + getRegisterGroups(1); // assert root is preserved + } + + + @Test + public void canRestoreRegisterGroups() throws Throwable { + int grpsIncrement = 3; + addRegisterGroups(grpsIncrement); + //Always able to restore to default + assertTrue(canRestoreDefaultGroups()); + } + + @Test + public void restoreRegisterGroups() throws Throwable { + int grpsIncrement = 3; + addRegisterGroups(grpsIncrement); + + restoreDefaultGroups(); + + // assert all groups are gone except root + getRegisterGroups(1); + } + + @Test + public void getRegisterNames() throws Throwable { + int grpsIncrement = 2; + addRegisterGroups(grpsIncrement); + IRegisterGroupDMContext[] groups = getRegisterGroups(3); // root + + // increment + + IRegisterDMContext[] regDmcs1 = getRegisters(groups[0]); + IRegisterDMContext[] regDmcs2 = getRegisters(groups[1]); + + IRegisterDMData[] regNames1 = getRegistersData(regDmcs1); + IRegisterDMData[] regNames2 = getRegistersData(regDmcs2); + + // assert the register names match on both groups + assertTrue(sameRegisterNames(regNames1, regNames2)); + } + + @Test + public void saveAndReadRegisterGroupData() throws Throwable { + //Only the default group is expected + int starting_sequence = 0; + + int grpsIncrement = 2; + addRegisterGroups(grpsIncrement); + getRegisterGroups(3); // root + 2 + + //The two steps below would ideally use a shutdown and the start of a new launch configuration within the same case. + //However the approach below accomplishes verification of saving and reading with out over complicating the current base test case structure. + + //trigger groups saving + saveRegGroups(); + + //trigger group reading from launch configuration + resetRegService(); + + IRegisterGroupDMContext[] groups = getRegisterGroups(3); // root + 2 + // Assert the last created group name + IRegisterGroupDMData groupData = getRegisterGroupData(groups[0]); + // 2 additional groups after creation of the base group in this test case + assertEquals("Group_" + (starting_sequence + grpsIncrement), groupData.getName()); + } + + /** + * All groups shall be able to write / update register values, These new value shall be propagated to any other + * group(s) containing this register + */ + @Test + public void writeRegisterFromUserGroup() throws Throwable { + // Define a subset of registers common to other register groups + // indexes (from, to) + final IRegisterDMContext[] regInRootGroup = getRegisters(0, 4); + String oirigVal = getModelDataForRegisterDataValue(regInRootGroup[0], IFormattedValues.NATURAL_FORMAT); + + // Get a handle to the execution contexts, same frame execution context for all actions + IFrameDMContext frameDmc = DMContexts.getAncestorOfType(regInRootGroup[0], IFrameDMContext.class); + + // create two user groups containing the same registers (new register instances based on root) + String groupNameOne = proposeGroupName(); + addGroup(groupNameOne, regInRootGroup); + + String groupNameTwo = proposeGroupName(); + addGroup(groupNameTwo, regInRootGroup); + + // Retrieve the existing groups, expected and validated to root + 2 + IRegisterGroupDMContext[] groups = getRegisterGroups(3); + + // Read registers from group one + // index 0 -> root group; index1 -> group one, index2 -> group Two + CompositeDMContext compositeDmc = new CompositeDMContext(new IDMContext[] { frameDmc, groups[1] }); + IRegisterDMContext[] groupOneRegisters = getRegisters(compositeDmc); + + // write a register value from register group one, register index 0 + Long iWrittenVal = Long.valueOf(oirigVal) + Long.valueOf(5); + String writtenValue = iWrittenVal.toString(); + List eventNotifications = writeRegisterWaitNotication(groupOneRegisters[0], + writtenValue, IFormattedValues.NATURAL_FORMAT); + + // Validate IRegistersChangedDMEvent event notifications, one notification per group to trigger UI refresh + assertNotNull("No IRegistersChangedDMEvent were generated from the register value update", eventNotifications); + assertEquals("Incorrect number of IRegistersChangedDMEvent notifications, expecting one per group", 3, + eventNotifications.size()); + + // read the register value from user group two + compositeDmc = new CompositeDMContext(new IDMContext[] { frameDmc, groups[2] }); + IRegisterDMContext[] groupTwoRegisters = getRegisters(compositeDmc); + String readVal = getModelDataForRegisterDataValue(groupTwoRegisters[0], IFormattedValues.NATURAL_FORMAT); + + // assert the value from group two has been updated + assertEquals( + "Register[0] Value read from group two does not correspond to updated value written from group one", + writtenValue, readVal); + + // read the register value from the root register group + readVal = getModelDataForRegisterDataValue(regInRootGroup[0], IFormattedValues.NATURAL_FORMAT); + + // assert the value from root group has also been updated + assertEquals( + "Register[0] Value read from root group does not correspond to updated value written from group one", + writtenValue, readVal); + + } + + /** + * Get an array with all available register groups + */ + private IRegisterGroupDMContext[] getRegisterGroups() throws Throwable { + + Query queryGroupsCtx = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.getRegisterGroups(fCompositeDmc, rm); + } + }; + + fRegService.getExecutor().execute(queryGroupsCtx); + + IRegisterGroupDMContext[] regGroupsDMCs = queryGroupsCtx.get(500, TimeUnit.MILLISECONDS); + + return (regGroupsDMCs); + } + + /** + * Request the existing groups and validate an expected count + */ + private IRegisterGroupDMContext[] getRegisterGroups(int expectedCount) throws Throwable { + IRegisterGroupDMContext[] regGroupsDMCs = getRegisterGroups(); + assertTrue("Number of groups present (" + regGroupsDMCs.length + ")" + ", and expected (" + expectedCount + ")", //$NON-NLS-1$ + regGroupsDMCs.length == expectedCount); + + return (regGroupsDMCs); + } + + private String proposeGroupName() throws Throwable { + return PROPOSE_GROUP_NAME_BASE + ++fGroupNameSuffix; + } + + private boolean canAddRegisterGroup(final IDMContext context) throws Throwable { + Query queryAction = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.canAddRegisterGroup(context, rm); + } + }; + + fRegService.getExecutor().submit(queryAction); + return queryAction.get(500, TimeUnit.MILLISECONDS); + } + + private boolean canEditRegisterGroup(final IRegisterGroupDMContext context) throws Throwable { + Query queryAction = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.canEditRegisterGroup(context, rm); + } + }; + + fRegService.getExecutor().submit(queryAction); + return queryAction.get(500, TimeUnit.MILLISECONDS); + } + + private boolean canRemoveRegisterGroups(final IRegisterGroupDMContext[] groupsContext) throws Throwable { + Query queryAction = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.canRemoveRegisterGroups(groupsContext, rm); + } + }; + + fRegService.getExecutor().submit(queryAction); + return queryAction.get(500, TimeUnit.MILLISECONDS); + } + + private void addGroup(final String groupName, final IRegisterDMContext[] regIndexes) throws Throwable { + + if (regIndexes == null || regIndexes.length < 1) { + fail("Invalid argument regIndexes"); + return; + } + + Query queryAction = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + IContainerDMContext contDmc = DMContexts.getAncestorOfType(regIndexes[0], IContainerDMContext.class); + fRegService.addRegisterGroup(contDmc, groupName, regIndexes, rm); + } + }; + + fRegService.getExecutor().submit(queryAction); + queryAction.get(500, TimeUnit.MILLISECONDS); + } + + private void editGroup(final IRegisterGroupDMContext group, final String newGroupName, final IRegisterDMContext[] regIndexes) throws Throwable { + + Query queryAction = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.editRegisterGroup(group, newGroupName, regIndexes, rm); + } + }; + + fRegService.getExecutor().submit(queryAction); + queryAction.get(500, TimeUnit.MILLISECONDS); + } + + private void removeGroups(final IRegisterGroupDMContext[] groups) throws Throwable { + + Query queryAction = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.removeRegisterGroups(groups, rm); + } + }; + + fRegService.getExecutor().submit(queryAction); + queryAction.get(500, TimeUnit.MILLISECONDS); + } + + private boolean canRestoreDefaultGroups() throws Throwable { + Query queryCanRestore = new Query() { + + @Override + protected void execute(DataRequestMonitor rm) { + //selection context not used for the time being + fRegService.canRestoreDefaultGroups(null, rm); + } + + }; + + fRegService.getExecutor().submit(queryCanRestore); + + //Validate, we can always restore to defaults + return queryCanRestore.get(500, TimeUnit.MILLISECONDS); + } + + private void restoreDefaultGroups() throws Throwable { + Query queryRestore = new Query() { + + @Override + protected void execute(DataRequestMonitor rm) { + //selection context not used for the time being + fRegService.restoreDefaultGroups(null, rm); + } + + }; + + fRegService.getExecutor().submit(queryRestore); + + queryRestore.get(500, TimeUnit.MILLISECONDS); + } + + private void resetRegService() throws Throwable { + assert(fRegService instanceof GDBRegisters); + final GDBRegisters regManager = (GDBRegisters) fRegService; + Query queryReset = new Query() { + + @Override + protected void execute(DataRequestMonitor rm) { + regManager.reset(rm); + } + + }; + + regManager.getExecutor().submit(queryReset); + + queryReset.get(500, TimeUnit.MILLISECONDS); + } + + private void saveRegGroups() throws Throwable { + assert(fRegService instanceof GDBRegisters); + final GDBRegisters regManager = (GDBRegisters) fRegService; + Query querySave = new Query() { + + @Override + protected void execute(DataRequestMonitor rm) { + regManager.save(); + rm.done(); + } + + }; + + regManager.getExecutor().submit(querySave); + + querySave.get(500, TimeUnit.MILLISECONDS); + } + + private IRegisterDMData getRegisterData(final IRegisterDMContext registerDmc) throws Throwable { + Query registerDataQ = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.getRegisterData(registerDmc, rm); + } + }; + + fRegService.getExecutor().submit(registerDataQ); + IRegisterDMData registerData = registerDataQ.get(500, TimeUnit.MILLISECONDS); + assertNotNull(registerData); + + return registerData; + } + + private FormattedValueDMData getRegisterValue(final IRegisterDMContext registerDmc) throws Throwable { + Query registerValueQ = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + FormattedValueDMContext valueDmc = new FormattedValueDMContext(fRegService, registerDmc, IFormattedValues.NATURAL_FORMAT); + fRegService.getFormattedExpressionValue(valueDmc, rm); + } + }; + + fRegService.getExecutor().submit(registerValueQ); + FormattedValueDMData registerValue = registerValueQ.get(500, TimeUnit.MILLISECONDS); + assertNotNull(registerValue); + + return registerValue; + } + + private IRegisterGroupDMData getRegisterGroupData(final IRegisterGroupDMContext groupDmc) throws Throwable { + Query groupDataQ = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + fRegService.getRegisterGroupData(groupDmc, rm); + } + }; + + fRegService.getExecutor().submit(groupDataQ); + IRegisterGroupDMData groupData = groupDataQ.get(500, TimeUnit.MILLISECONDS); + assertNotNull(groupData); + + return groupData; + } + + private IRegisterGroupDMData[] getRegisterGroupsData(final IDMContext dmc) throws Throwable { + Query groupDataQ = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + getRegisterGroupsData(dmc, rm); + } + }; + + fRegService.getExecutor().submit(groupDataQ); + IRegisterGroupDMData[] groupsData = groupDataQ.get(500, TimeUnit.MILLISECONDS); + assertNotNull(groupsData); + + return groupsData; + } + + private void getRegisterGroupsData(final IDMContext dmc, final DataRequestMonitor rm) { + assert (dmc != null); + final DsfExecutor executor = fRegService.getExecutor(); + // First get all register group contexts, any register context can be used to resolve the container context + fRegService.getRegisterGroups(dmc, new DataRequestMonitor(executor, rm) { + @Override + protected void handleSuccess() { + final IRegisterGroupDMContext[] groupsCtx = getData(); + assert (groupsCtx != null); + + final IRegisterGroupDMData[] groupsData = new IRegisterGroupDMData[groupsCtx.length]; + + final CountingRequestMonitor crm = new CountingRequestMonitor(executor, rm) { + @Override + protected void handleCompleted() { + rm.setData(groupsData); + rm.done(); + } + }; + + // Resolve all register group data + for (int i = 0; i < groupsCtx.length; i++) { + final int index = i; + fRegService.getRegisterGroupData(groupsCtx[index], new DataRequestMonitor(executor, crm) { + @Override + protected void handleSuccess() { + groupsData[index] = getData(); + crm.done(); + } + }); + } + + crm.setDoneCount(groupsCtx.length); + } + }); + } + + private IRegisterDMContext[] getRegisters(int from, int to) throws Throwable { + MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); + IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); + final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); + + // Shall not ask for more than is available + assertTrue(regDMCs.length > to); + + // Retrieve the register range + final IRegisterDMContext[] regRange = Arrays.copyOfRange(regDMCs, from, to); + + return regRange; + } + + private IRegisterGroupDMContext addDefaultUserGroup() throws Throwable { + // Define a subset of registers to create a register group + final IRegisterDMContext[] regInGroup = getRegisters(0, 4); + // Request the addition of the new group + addGroup(GROUP_X, regInGroup); + + // Retrieve the existing groups, expected and validated to 2 + IRegisterGroupDMContext[] groups = getRegisterGroups(2); + + // The groups are returned in reversed order to present latest created + // first i.e. index 0 + // Our new group shall be at the top then i.e. 0 + IFrameDMContext frameDmc = DMContexts.getAncestorOfType(regInGroup[0], IFrameDMContext.class); + CompositeDMContext compositeDmc = new CompositeDMContext(new IDMContext[]{groups[0], frameDmc}); + IRegisterDMContext[] readRegisters = getRegisters(compositeDmc); + + // Same objects and same order expected, although different parents + assertTrue(sameData(regInGroup, readRegisters, false)); + return groups[0]; + } + + private IRegisterGroupDMContext[] addRegisterGroups(int numberOfNewGroups) throws Throwable { + // Define a subset of registers to associate to the new register groups + final IRegisterDMContext[] regInGroup = getRegisters(0, 4); + for (int i = 0; i < numberOfNewGroups; i++) { + String groupName = proposeGroupName(); + addGroup(groupName, regInGroup); + } + + // Expected number of groups = Root + numberofNewGroups + return getRegisterGroups(1 + numberOfNewGroups); + } + + /** + * Check the register Data entry names are in the same order + */ + private boolean sameRegisterNames(IRegisterDMData[] regNames1, IRegisterDMData[] regNames2) { + boolean same = false; + if (regNames1.length == regNames2.length) { + for (int i = 0; i < regNames1.length; i++) { + if (regNames1[i].getName().equals(regNames2[i].getName())) { + continue; + } else { + // Found a different name, Not the same !! + return false; + } + } + + // All names matched !! + return true; + } + + return same; + } + + private boolean sameData(IRegisterDMContext[] regArrOne, IRegisterDMContext[] regArrTwo, boolean sameParentGroup) throws Throwable { + if (regArrOne.length != regArrTwo.length) { + return false; + } + + for (int i=0; i< regArrOne.length; i++) { + if (sameParentGroup) { + //same group parent expected + final IRegisterGroupDMContext parentGroupOne = DMContexts.getAncestorOfType(regArrOne[i], IRegisterGroupDMContext.class); + final IRegisterGroupDMContext parentGroupTwo = DMContexts.getAncestorOfType(regArrTwo[i], IRegisterGroupDMContext.class); + if(!parentGroupOne.equals(parentGroupTwo)) { + return false; + } + } + + //same data + IRegisterDMData dataOne = getRegisterData(regArrOne[i]); + IRegisterDMData dataTwo = getRegisterData(regArrTwo[i]); + + if (!dataOne.getName().equals(dataTwo.getName())) { + return false; + } + + //same value + FormattedValueDMData valueOne = getRegisterValue(regArrOne[i]); + FormattedValueDMData valueTwo = getRegisterValue(regArrTwo[i]); + if (!valueOne.getFormattedValue().equals(valueTwo.getFormattedValue())) { + return false; + } + } + + //All data is the same + return true; + } + + /** + * Resolve from proposed name to group sequence number e.g Group_5 -> 5 + */ + private int resolveGroupNameSequence(String groupName) { + int sequence = 0; + String[] strSequence = groupName.split("_"); + assertTrue(strSequence.length == 2); + sequence = Integer.parseInt(strSequence[1]); + return sequence; + } + } diff --git a/dsf/org.eclipse.cdt.dsf.ui/plugin.xml b/dsf/org.eclipse.cdt.dsf.ui/plugin.xml index e8b4e79abf5..ff1d4933573 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/plugin.xml +++ b/dsf/org.eclipse.cdt.dsf.ui/plugin.xml @@ -340,7 +340,71 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java index 0761ffcf449..794833b2f61 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2013 Wind River Systems, Inc. and others. + * Copyright (c) 2009, 2014 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -9,6 +9,7 @@ * Wind River Systems - initial API and implementation * Patrick Chuong (Texas Instruments) - Bug 315446: Invalid event breakpoint type (group) name * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865) + * Alvaro Sanchez-Leon (Ericsson AB) - Support Register Groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.dsf.debug.internal.ui; @@ -18,6 +19,14 @@ public class Messages extends NLS { public static String ToggleBreakpointsTargetFactory_description; public static String ToggleBreakpointsTargetFactory_name; public static String DsfUIStepIntoEditorSelection; + public static String RegisterGroupInfo; + public static String Information; + public static String DefaultRegistersGroupName; + public static String ProposeGroupNameRoot; + public static String RegisterGroupConfirmRestoreTitle; + public static String RegisterGroupConfirmRestoreMessage; + public static String RegisterGroupRestore; + public static String RegisterGroupRestoreCancel; static { // initialize resource bundle diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties index 37451dbd583..7c11584161e 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2009, 2013 Wind River Systems and others. +# Copyright (c) 2009, 2014 Wind River Systems and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at @@ -9,9 +9,19 @@ # Wind River Systems - initial API and implementation # Ericsson - added Tracepoint support # Ericsson - added Step into selection support +# Ericsson - Support Register Groups ############################################################################### ToggleBreakpointsTargetFactory_description=Standard C/C++ breakpoint type. ToggleBreakpointsTargetFactory_name=C/C++ Breakpoints DsfUIStepIntoEditorSelection=Step Into +Information=Information +RegisterGroupInfo=Register Group +DefaultRegistersGroupName=New Group +ProposeGroupNameRoot=Group_ +RegisterGroupConfirmRestoreTitle=Register Groups - Confirm Restore +RegisterGroupConfirmRestoreMessage=Are you sure you want to restore to the default register group(s) ? +RegisterGroupRestore=OK +RegisterGroupRestoreCancel=Cancel + diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/AbstractDsfRegisterGroupActions.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/AbstractDsfRegisterGroupActions.java new file mode 100644 index 00000000000..9514e57ad22 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/AbstractDsfRegisterGroupActions.java @@ -0,0 +1,1010 @@ +/******************************************************************************* + * Copyright (c) 2014 Ericsson AB 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: + * Alvaro Sanchez-Leon (Ericsson) - First Implementation and API (Bug 235747) + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.internal.ui.actions; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.debug.core.model.IRegisterDescriptor; +import org.eclipse.cdt.debug.internal.core.model.IRegisterGroupDescriptor; +import org.eclipse.cdt.debug.internal.ui.actions.RegisterGroupDialog; +import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.Query; +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.internal.ui.Messages; +import org.eclipse.cdt.dsf.debug.service.IRegisters; +import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext; +import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData; +import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext; +import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData; +import org.eclipse.cdt.dsf.debug.service.IRegisters2; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchPart; + +public abstract class AbstractDsfRegisterGroupActions extends AbstractHandler { + private static final String BLANK_STRING = ""; //$NON-NLS-1$ + private static final String REG_GROUP_ACTION_FAILED = "Register Group Action failed\n"; //$NON-NLS-1$ + + private class RegisterGroupDialogRunnable implements Runnable { + private String fGroupName = BLANK_STRING; + private IRegisterDescriptor[] fSelectedRegisters = null; + private final IRegisterDescriptor[] fallRegisters; + private final Shell fShell; + private final DataRequestMonitor fMonitor; + + private RegisterGroupDialogRunnable(Shell shell, String groupName, IRegisterDescriptor[] allRegisters, + IRegisterDescriptor[] selectedRegisters, DataRequestMonitor rm) { + fallRegisters = allRegisters; + fSelectedRegisters = selectedRegisters; + fShell = shell; + fGroupName = groupName; + fMonitor = rm; + } + + @Override + public void run() { + RegisterGroupDialog dialog = new RegisterGroupDialog(fShell, fGroupName, fallRegisters, fSelectedRegisters); + if (dialog.open() == Window.OK) { + String groupName = dialog.getName(); + IRegisterDescriptor[] iSelectedRegisters = dialog.getDescriptors(); + IRegisterGroupDescriptor groupDescriptor = createGroupDescriptor(groupName, iSelectedRegisters); + + fMonitor.setData(groupDescriptor); + } else { + fMonitor.cancel(); + return; + } + + fMonitor.done(); + } + } + + private class RegisterDescriptor implements IRegisterDescriptor { + private final IRegisterDMContext fRegContext; + private String fOriginalGroupName = BLANK_STRING; + private String fName = BLANK_STRING; + + private RegisterDescriptor(String groupName, IRegisterDMContext regContext, String name) { + fRegContext = regContext; + fName = name; + // initial group Name + fOriginalGroupName = groupName; + } + + @Override + public String getName() { + return fName; + } + + @Override + public String getGroupName() { + return fOriginalGroupName; + } + } + + private class SelectionDMContext { + private final IDMContext fcontext; + private final DsfSession fsession; + + private SelectionDMContext(IStructuredSelection selection) throws DebugException { + if (!(selection.getFirstElement() instanceof IDMVMContext)) { + abort("Unrecognized element from the provided register selection"); //$NON-NLS-1$ + } + + // Resolve the context + IDMVMContext context = (IDMVMContext) selection.getFirstElement(); + fcontext = context.getDMContext(); + + // Resolve the session + String sessionId = fcontext.getSessionId(); + fsession = DsfSession.getSession(sessionId); + + if (fsession == null || !(fsession.isActive())) { + abort("Sesssion inactive"); //$NON-NLS-1$ + } + } + + /** + * This method has to be called under the executor's thread + */ + public IRegisters2 resolveService() throws DebugException { + // Resolve the registers service + DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), fsession.getId()); + IRegisters service = tracker.getService(IRegisters.class, null); + + tracker.dispose(); + + if (!(service instanceof IRegisters2)) { + abort("Unable to resolve IRegisters2 service"); //$NON-NLS-1$ + } + + return (IRegisters2) service; + } + + private void abort(String message) throws DebugException { + // Interrupt on error + IStatus status = new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IStatus.ERROR, message, null); + throw new DebugException(status); + } + + } + + private interface DialogRegisterProvider { + public IRegisterDescriptor[] getAllRegisters(); + + public IRegisterDescriptor[] getcheckedRegisters(); + } + + protected void addRegisterGroup(final IWorkbenchPart part, final IStructuredSelection selection) { + try { + final SelectionDMContext selectionContext = new SelectionDMContext(selection); + selectionContext.fsession.getExecutor().execute(new DsfRunnable() { + + @Override + public void run() { + final IRegisters2 registersService; + try { + registersService = selectionContext.resolveService(); + } catch (CoreException e) { + failed(e); + return; + } + + // continue to process + processAddRegisterGroup(part.getSite().getShell(), selectionContext, + resolveSelectedRegisters(selection), registersService); + }}); + + } catch (DebugException e) { + } + } + + protected boolean canAddRegisterGroup(IWorkbenchPart part, IStructuredSelection selection) { + try { + final SelectionDMContext selectionContext = new SelectionDMContext(selection); + Query query = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + IRegisters2 registersService; + try { + registersService = selectionContext.resolveService(); + } catch (DebugException e) { + rm.setData(false); + rm.done(); + return; + } + + if (registersService != null) { + registersService.canAddRegisterGroup(selectionContext.fcontext, rm); + } else { + rm.setData(false); + rm.done(); + } + } + }; + selectionContext.fsession.getExecutor().execute(query); + return query.get(); + } catch (RejectedExecutionException e) { + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } catch (DebugException e1) { + } + + return false; + } + + protected void editRegisterGroup(final IWorkbenchPart part, IStructuredSelection selection) { + try { + final SelectionDMContext selectionContext = new SelectionDMContext(selection); + + selectionContext.fsession.getExecutor().execute(new DsfRunnable() { + @Override + public void run() { + // Create a services tracker + final IRegisters2 registersService; + try { + registersService = selectionContext.resolveService(); + } catch (CoreException e) { + failed(e); + return; + } + + processEditRegisterGroup(part.getSite().getShell(), selectionContext, + registersService); + } + + }); + } catch (DebugException e) { + } + } + + protected boolean canEditRegisterGroup(IWorkbenchPart part, IStructuredSelection selection) { + try { + final SelectionDMContext selectionContext = new SelectionDMContext(selection); + final IDMContext context = selectionContext.fcontext; + + // The group to be edited needs to be selected + if (!(context instanceof IRegisterGroupDMContext)) { + return false; + } + + Query query = new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + IRegisters2 registersService; + try { + registersService = selectionContext.resolveService(); + } catch (DebugException e) { + rm.setData(false); + rm.done(); + return; + } + + if (registersService != null) { + registersService.canEditRegisterGroup((IRegisterGroupDMContext) context, rm); + } else { + rm.setData(false); + rm.done(); + } + } + }; + selectionContext.fsession.getExecutor().execute(query); + return query.get(); + + } catch (RejectedExecutionException e) { + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } catch (DebugException e1) { + } + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#removeRegisterGroups(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + protected void removeRegisterGroups(IWorkbenchPart part, IStructuredSelection selection) { + try { + final SelectionDMContext selectionContext = new SelectionDMContext(selection); + + final IRegisterGroupDMContext[] groups = resolveSelectedGroups(selection); + selectionContext.fsession.getExecutor().execute(new DsfRunnable() { + @Override + public void run() { + IRegisters2 registersService; + try { + registersService = selectionContext.resolveService(); + } catch (CoreException e) { + failed(e); + return; + } + + registersService.removeRegisterGroups(groups, new RequestMonitor(registersService.getExecutor(), null) { + }); + } + }); + } catch (DebugException e) { + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#canRemoveRegisterGroups(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + protected boolean canRemoveRegisterGroups(IWorkbenchPart part, IStructuredSelection selection) { + final SelectionDMContext selectionContext; + try { + selectionContext = new SelectionDMContext(selection); + } catch (DebugException e) { + // No DM context present or group registers service found in the selection + return false; + } + + //resolve the selected groups + final IRegisterGroupDMContext[] groups = resolveSelectedGroups(selection); + if (groups == null || groups.length < 1){ + return false; + } + + //Prepare to Query the service and check if the selected groups can be removed + Query query = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + IRegisters2 regService; + try { + regService = selectionContext.resolveService(); + } catch (DebugException e) { + // Unable to resolve the registers service + rm.setData(false); + rm.done(); + return; + } + + regService.canRemoveRegisterGroups(groups, rm); + } + }; + + //Execute the query + selectionContext.fsession.getExecutor().execute(query); + + try { + // return the answer from the service + return query.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + + // No positive answer from the service + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#restoreDefaultGroups(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + protected void restoreDefaultGroups(IWorkbenchPart part, IStructuredSelection selection) { + if (!restoreConfirmed()) { + return; + } + + try { + final SelectionDMContext selectionContext = new SelectionDMContext(selection); + + selectionContext.fsession.getExecutor().execute(new DsfRunnable() { + @Override + public void run() { + IRegisters2 registersService; + try { + registersService = selectionContext.resolveService(); + } catch (CoreException e) { + failed(e); + return; + } + + // no success handler needed + registersService.restoreDefaultGroups(null, new RequestMonitor(registersService.getExecutor(), null)); + } + }); + } catch (DebugException e) { + failed(e); + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.ui.actions.IRegisterGroupActionsTarget#canRestoreDefaultGroups(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.IStructuredSelection) + */ + protected boolean canRestoreDefaultGroups(IWorkbenchPart part, IStructuredSelection selection) { + final SelectionDMContext selectionContext; + try { + selectionContext = new SelectionDMContext(selection); + } catch (DebugException e) { + // No DM context present or group registers service found in the selection + return false; + } + + //Prepare to Query the service + Query query = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + IRegisters2 regService; + try { + regService = selectionContext.resolveService(); + } catch (DebugException e) { + // Unable to resolve the registers service + rm.setData(false); + rm.done(); + return; + } + + regService.canRestoreDefaultGroups(selectionContext.fcontext, rm); + } + }; + + //Execute the query + selectionContext.fsession.getExecutor().execute(query); + + try { + // return the answer from the service + return query.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + + // No positive answer from the service + return false; + } + + @ConfinedToDsfExecutor("selectionContext.fsession.getExecutor()") + private void processAddRegisterGroup(final Shell shell, final SelectionDMContext selectionContext, final IRegisterDMContext[] selectedRegisters, + final IRegisters2 regServiceManager) { + + final DsfSession session = selectionContext.fsession; + final DsfExecutor executor = session.getExecutor(); + + final IContainerDMContext contDmc = DMContexts.getAncestorOfType(selectionContext.fcontext, IContainerDMContext.class); + // Using the container context to get all existing registers from the target instead of a limited set of registers for a selected group + regServiceManager.getRegisters(contDmc, new DataRequestMonitor( + executor, null) { + + @Override + protected void handleSuccess() { + // Get Register Contexts + final IRegisterDMContext[] rootRegisters = getData(); + + if (rootRegisters.length < 1) { + //The target is expected to have registers, an error has happened ! + assert false; + noRegisterGroupFoundErr("Add Register Group", this); //$NON-NLS-1$ + return; + } + + //Find the root register group, containing all the registers associated to a target, from any of the root registers + final IRegisterGroupDMContext rootGroupDmc = DMContexts.getAncestorOfType(rootRegisters[0], IRegisterGroupDMContext.class); + + // Get data for all available registers + getRegistersData(rootRegisters, regServiceManager, new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + final IRegisterDMData[] rootRegistersData = getData(); + + getRegistersData(selectedRegisters, regServiceManager, new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + // Get data for all selected registers i.e. selected for the new group + final IRegisterDMData[] selectedRegistersData = getData(); + + //Need the root group name to build register descriptors + regServiceManager.getRegisterGroupData(rootGroupDmc, + new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + final IRegisterGroupDMData rootGroupData = getData(); + // request for the next unused group name to propose it to the user + proposeGroupName(rootRegisters, regServiceManager, new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + String proposedGroupName = getData(); + + String rootGroupName = (rootGroupData == null) ? BLANK_STRING + : rootGroupData.getName(); + // Create the Register descriptors + DialogRegisterProvider descriptors = buildDescriptors( + rootGroupName, rootRegisters, + rootRegistersData, + selectedRegistersData); + // Create Dialog Resolve selection to DSF + // Registers + getDialogSelection( + shell, + proposedGroupName, + descriptors.getAllRegisters(), + descriptors.getcheckedRegisters(), + new DataRequestMonitor( + executor, null) { + @Override + protected void handleSuccess() { + try { + addRegisterGroup( + regServiceManager, + getData(), contDmc); + } catch (CoreException e) { + failed(e); + } + }; + }); + } + }); + + } + }); + } + }); + } + }); + } + + }); + } + + private void noRegisterGroupFoundErr(String msgOrigin, RequestMonitor rm) { + String message = msgOrigin + ": Unable to resolve root Group"; //$NON-NLS-1$ + IStatus status = new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, + REG_GROUP_ACTION_FAILED + message, new Exception(message)); + DsfUIPlugin.log(status); + rm.setStatus(status); + rm.done(); + } + + private void proposeGroupName(IRegisterDMContext[] registers, final IRegisters2 regServiceManager, final DataRequestMonitor rm) { + assert(registers != null && registers.length > 0); + + final DsfExecutor executor = regServiceManager.getExecutor(); + if (registers != null && registers.length > 0) { + //First get all register group contexts, any register context can be used to resolve the container context + regServiceManager.getRegisterGroups(registers[0], new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + IRegisterGroupDMContext[] groupsCtx = getData(); + assert (groupsCtx != null); + + final IRegisterGroupDMData[] groupsData = new IRegisterGroupDMData[groupsCtx.length]; + + final CountingRequestMonitor crm = new CountingRequestMonitor(executor, rm) { + @Override + protected void handleCompleted() { + //GroupsData is resolved now + //Select an unused name + String unusedGroupName = Messages.ProposeGroupNameRoot + (resolveGroupNameWaterMark(groupsData) + 1); + rm.setData(unusedGroupName); + rm.done(); + } + }; + + //Resolve all register group data + for (int i=0; i < groupsCtx.length; i++) { + final int index = i; + regServiceManager.getRegisterGroupData(groupsCtx[index], new DataRequestMonitor(executor, crm){ + @Override + protected void handleSuccess() { + groupsData[index] = getData(); + crm.done(); + } + }); + } + + crm.setDoneCount(groupsCtx.length); + } + }); + } else { + //Should not happen + rm.setData(Messages.DefaultRegistersGroupName); + rm.done(); + } + } + + // Adjust water mark suffix used to suggest register group names + private Integer resolveGroupNameWaterMark(IRegisterGroupDMData[] groupsData) { + // check only for this name pattern + Pattern pattern = Pattern.compile("^group_(\\d*)$"); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(""); //$NON-NLS-1$ + int water_mark = 0; + for (IRegisterGroupDMData groupData : groupsData) { + // Normalize the name to lower case comparison + String name = groupData.getName().trim().toLowerCase(); + // tracking proposed group names e.d. Group_1, Group_2, etc.., + // otherwise no need to update the water mark + if (matcher.reset(name).matches()) { + // Obtain the numerical suffix + String number = matcher.replaceAll("$1"); //$NON-NLS-1$ + try { + int nameSequence = Integer.valueOf(number).intValue(); + if (nameSequence > water_mark) { + // The new value is bigger so lets move up the water mark + water_mark = nameSequence; + } + } catch (NumberFormatException e) { + // Quite unlikely and only causing a possibility to + // propose a group name that already exists. + } + } + } + + return Integer.valueOf(water_mark); + } + + @ConfinedToDsfExecutor("selectionContext.fsession.getExecutor()") + private void processEditRegisterGroup(final Shell shell, final SelectionDMContext selectionContext, final IRegisters2 regServiceManager) { + + final DsfSession session = selectionContext.fsession; + final DsfExecutor executor = session.getExecutor(); + + // Get a handle to the context of the group being edited + final IRegisterGroupDMContext groupDmc = DMContexts.getAncestorOfType(selectionContext.fcontext, + IRegisterGroupDMContext.class); + + // Getting the children of the selected group + regServiceManager.getRegisters(selectionContext.fcontext, + new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + // Get children Register Contexts + final IRegisterDMContext[] childRegisters = getData(); + + final IContainerDMContext contDmc = DMContexts.getAncestorOfType(selectionContext.fcontext, IContainerDMContext.class); + // Using the container context to get all existing registers from the target instead of a limited set of registers for a selected group + // This is needed to populate the dialog with all available registers to pick from + regServiceManager.getRegisters(contDmc, new DataRequestMonitor( + executor, null) { + @Override + protected void handleSuccess() { + final IRegisterDMContext[] rootRegisters = getData(); + + if (rootRegisters.length < 1) { + //The target is expected to have a root register group and associated registers, an error has happened ! + assert false; + noRegisterGroupFoundErr("Edit Register Group", this); //$NON-NLS-1$ + return; + } + + // We need to resolve the names for all root registers + getRegistersData(rootRegisters, regServiceManager, new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + final IRegisterDMData[] rootRegistersData = getData(); + + getRegistersData(childRegisters, regServiceManager, new DataRequestMonitor(executor, null) { + @Override + protected void handleSuccess() { + // Get register data for all selected registers i.e. selected for the new group + final IRegisterDMData[] childRegisterData = getData(); + + // Need to get the parent group name. Used on the register descriptors + final IRegisterGroupDMContext rootGroupDmc = DMContexts.getAncestorOfType(rootRegisters[0], IRegisterGroupDMContext.class); + regServiceManager.getRegisterGroupData(rootGroupDmc, + new DataRequestMonitor( + executor, null) { + @Override + protected void handleSuccess() { + IRegisterGroupDMData rootGroupData = getData(); + final String rootGroupName = (rootGroupData == null) ? BLANK_STRING + : rootGroupData.getName(); + + regServiceManager.getRegisterGroupData(groupDmc, + new DataRequestMonitor( + executor, null) { + @Override + protected void handleSuccess() { + // Resolve the name of the selected group being edited + String selGroupName = getData().getName(); + // Create the Register descriptors to + // access all children registers + DialogRegisterProvider descriptors = buildDescriptors( + rootGroupName, rootRegisters, + rootRegistersData, + childRegisterData); + + // Create Dialog to Resolve new user + // selection of group name and registers + getDialogSelection( + shell, + selGroupName, + descriptors.getAllRegisters(), + descriptors + .getcheckedRegisters(), + new DataRequestMonitor( + executor, null) { + @Override + protected void handleSuccess() { + try { + editRegisterGroup( + groupDmc, + regServiceManager, + getData()); + } catch (CoreException e) { + failed(e); + } + }; + }); + } + }); + }; + + }); + } + }); + + } + }); + } + }); + } + }); + } + + private IRegisterGroupDMContext[] resolveSelectedGroups(IStructuredSelection selection) { + IRegisterGroupDMContext[] selectedGroups = null; + List groupList = new ArrayList(); + if (selection != null && !selection.isEmpty()) { + for (Iterator iterator = selection.iterator(); iterator.hasNext();) { + Object element = iterator.next(); + if (element instanceof IDMVMContext) { + IDMContext dmContext = ((IDMVMContext) element).getDMContext(); + // Make sure this selection is a group + if (dmContext instanceof IRegisterGroupDMContext) { + IRegisterGroupDMContext groupDmc = (IRegisterGroupDMContext) dmContext; + groupList.add(groupDmc); + } + } + } + + } + + selectedGroups = groupList.toArray(new IRegisterGroupDMContext[groupList.size()]); + return selectedGroups; + } + + @ConfinedToDsfExecutor("selectionContext.fsession.getExecutor()") + private IRegisterDMContext[] resolveSelectedRegisters(IStructuredSelection selection) { + List selectedRegistersList = new ArrayList(); + for (Iterator iterator = selection.iterator(); iterator.hasNext();) { + Object element = iterator.next(); + IDMVMContext regContext = null; + if (element instanceof IDMVMContext) { + regContext = (IDMVMContext) element; + IRegisterDMContext registerDmc = DMContexts.getAncestorOfType(regContext.getDMContext(), + IRegisterDMContext.class); + if (registerDmc != null) { + selectedRegistersList.add(registerDmc); + } + } + } + + IRegisterDMContext[] selectedRegisters = selectedRegistersList + .toArray(new IRegisterDMContext[selectedRegistersList.size()]); + return selectedRegisters; + } + + @ConfinedToDsfExecutor("selectionContext.fsession.getExecutor()") + private IRegisterDMContext[] getRegisterContexts(IRegisterDescriptor[] registerDescriptors) throws CoreException { + IRegisterDMContext[] regContexts = new IRegisterDMContext[registerDescriptors.length]; + for (int i = 0; i < registerDescriptors.length; i++) { + if (registerDescriptors[i] instanceof RegisterDescriptor) { + regContexts[i] = ((RegisterDescriptor) registerDescriptors[i]).fRegContext; + } else { + // Interrupt on error + IStatus status = new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IStatus.ERROR, + "Unexpected IRegisterDescription instance type", null); //$NON-NLS-1$ + throw new CoreException(status); + } + } + + return regContexts; + } + + @ConfinedToDsfExecutor("selectionContext.fsession.getExecutor()") + private void getDialogSelection(Shell shell, String originalGroupName, + IRegisterDescriptor[] allRegisters, IRegisterDescriptor[] checkedRegisters, + DataRequestMonitor rm) { + RegisterGroupDialogRunnable dialog = new RegisterGroupDialogRunnable(shell, originalGroupName, allRegisters, + checkedRegisters, rm); + shell.getDisplay().asyncExec(dialog); + } + + private IRegisterGroupDescriptor createGroupDescriptor(final String groupName, + final IRegisterDescriptor[] iSelectedRegisters) { + IRegisterGroupDescriptor groupDescriptor = new IRegisterGroupDescriptor() { + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public String getName() { + return groupName; + } + + @Override + public IRegisterDescriptor[] getChildren() throws CoreException { + return iSelectedRegisters; + } + }; + + return groupDescriptor; + } + + /** + * Build descriptor adapters to dialog interface both all registers as well as registers to be pre-selected on the + * dialog + * + * @param checkedRegistersData + */ + @ConfinedToDsfExecutor("selectionContext.fsession.getExecutor()") + private DialogRegisterProvider buildDescriptors(String groupName, IRegisterDMContext[] registers, + IRegisterDMData[] registerData, IRegisterDMData[] checkedRegistersData) { + assert (registers.length == registerData.length); + + List checkedDescriptorsList = new ArrayList(); + + final RegisterDescriptor[] regDescriptors = new RegisterDescriptor[registers.length]; + + Map mapNameToRegDescriptor = new HashMap(); + + for (int i = 0; i < registers.length; i++) { + regDescriptors[i] = new RegisterDescriptor(groupName, registers[i], registerData[i].getName()); + mapNameToRegDescriptor.put(regDescriptors[i].getName(), regDescriptors[i]); + } + + for (int i = 0; i < checkedRegistersData.length; i++) { + // Resolve the descriptor by name + RegisterDescriptor descriptor = mapNameToRegDescriptor.get(checkedRegistersData[i].getName()); + + // All checked registers are expected to be part of the complete list + assert (descriptor != null); + + // prevent duplicates or null values, duplicates are possible since the selected registers + // may come from different groups + if (descriptor != null && !checkedDescriptorsList.contains(descriptor)) { + checkedDescriptorsList.add(descriptor); + } + } + + final RegisterDescriptor[] checkedRegDescriptors = checkedDescriptorsList + .toArray(new RegisterDescriptor[checkedDescriptorsList.size()]); + + DialogRegisterProvider provider = new DialogRegisterProvider() { + @Override + public IRegisterDescriptor[] getcheckedRegisters() { + return checkedRegDescriptors; + } + + @Override + public IRegisterDescriptor[] getAllRegisters() { + return regDescriptors; + } + }; + + return provider; + } + + @ConfinedToDsfExecutor("selectionContext.fsession.getExecutor()") + private void addRegisterGroup(IRegisters2 regServiceManager, + IRegisterGroupDescriptor groupDescriptor, IContainerDMContext contDmc) throws CoreException { + IRegisterDescriptor[] selectedRegisters = groupDescriptor.getChildren(); + if (selectedRegisters != null) { + String groupName = groupDescriptor.getName(); + // Register the addition of the group and notify the change + IRegisterDMContext[] registers = getRegisterContexts(selectedRegisters); + regServiceManager.addRegisterGroup(contDmc, groupName, registers, new RequestMonitor( + regServiceManager.getSession().getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus() != null && getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) { + // This user request is not supported, notify the user + notifyUser(getStatus().getMessage()); + } + + }; + }); + } + } + + @ConfinedToDsfExecutor("selectionContext.fsession.getExecutor()") + private void editRegisterGroup(IRegisterGroupDMContext group, IRegisters2 regServiceManager, + IRegisterGroupDescriptor groupDescriptor) throws CoreException { + IRegisterDescriptor[] selectedRegisters = groupDescriptor.getChildren(); + if (selectedRegisters != null) { + String groupName = groupDescriptor.getName(); + // Register the addition of the group and notify the change + regServiceManager.editRegisterGroup(group, groupName, getRegisterContexts(selectedRegisters), + new RequestMonitor(regServiceManager.getSession().getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus() != null && getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) { + // This user request is not supported, notify the user + notifyUser(getStatus().getMessage()); + } + + }; + }); + } + } + + private void failed(Throwable e) { + IStatus status = new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, + REG_GROUP_ACTION_FAILED + e.getMessage(), e); + DsfUIPlugin.log(status); + } + + private void notifyUser(final String message) { + + Runnable runnable = new Runnable() { + @Override + public void run() { + Shell parent = DsfUIPlugin.getActiveWorkbenchShell(); + if (parent != null) { + MessageDialog.openInformation(parent, Messages.Information, Messages.RegisterGroupInfo + ": " + message); //$NON-NLS-1$ + } + } + }; + + Display.getDefault().asyncExec(runnable); + } + + /** + * @return true - OK to restore + */ + private boolean restoreConfirmed() { + ConfirmRestoreDialog restoreDialog = new ConfirmRestoreDialog(); + Display.getDefault().syncExec(restoreDialog); + + return restoreDialog.fRestore; + } + + private class ConfirmRestoreDialog implements Runnable { + + private Boolean fRestore = false; + + @Override + public void run() { + Shell parent = DsfUIPlugin.getActiveWorkbenchShell(); + if (parent != null) { + + String title = Messages.RegisterGroupConfirmRestoreTitle; + String message = Messages.RegisterGroupConfirmRestoreMessage; + String[] buttonLabels = new String[]{Messages.RegisterGroupRestore, Messages.RegisterGroupRestoreCancel, + }; + MessageDialog dialog = new MessageDialog(parent, title, null, message, MessageDialog.QUESTION, + buttonLabels, 0); + int res = dialog.open(); + if (res == 0) { // RESTORE + fRestore = true; + } else if (res == 1) { // CANCEL + fRestore = false; + } + } + } + + } + + + private void getRegistersData(IRegisterDMContext[] regDMCs, IRegisters2 regService, final DataRequestMonitor rm) { + final IRegisterDMData[] regDataArray = new IRegisterDMData[regDMCs.length]; + final DsfExecutor executor = regService.getExecutor(); + + final CountingRequestMonitor crm = new CountingRequestMonitor(executor, rm) { + @Override + protected void handleSuccess() { + rm.setData(regDataArray); + rm.done(); + } + }; + + for (int i = 0; i < regDMCs.length; i++) { + final int index = i; + regService.getRegisterData(regDMCs[index], new DataRequestMonitor(executor, crm) { + @Override + protected void handleSuccess() { + regDataArray[index] = getData(); + crm.done(); + } + }); + } + + crm.setDoneCount(regDMCs.length); + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfAddRegisterGroupCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfAddRegisterGroupCommand.java new file mode 100644 index 00000000000..7e89dac057e --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfAddRegisterGroupCommand.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.internal.ui.actions; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISources; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Command performing adding a register group. + * @since 2.4 + */ +public class DsfAddRegisterGroupCommand extends AbstractDsfRegisterGroupActions { + @Override + public void setEnabled(Object evaluationContext) { + boolean state = false; + if (evaluationContext instanceof IEvaluationContext) { + Object s = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); + Object p = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_PART_NAME); + if (s instanceof IStructuredSelection && p instanceof IWorkbenchPart) { + state = canAddRegisterGroup((IWorkbenchPart)p, (IStructuredSelection)s); + } + } + setBaseEnabled(state); + } + + @Override + public Object execute(ExecutionEvent event) { + ISelection selection = HandlerUtil.getCurrentSelection(event); + IWorkbenchPart part = HandlerUtil.getActivePart(event); + if (selection instanceof IStructuredSelection) { + addRegisterGroup(part, (IStructuredSelection)selection); + } + return null; + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfEditRegisterGroupCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfEditRegisterGroupCommand.java new file mode 100644 index 00000000000..5872ea1a049 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfEditRegisterGroupCommand.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.internal.ui.actions; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISources; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Command performing adding a register group. + * @since 2.4 + */ +public class DsfEditRegisterGroupCommand extends AbstractDsfRegisterGroupActions { + @Override + public void setEnabled(Object evaluationContext) { + boolean state = false; + if (evaluationContext instanceof IEvaluationContext) { + Object s = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); + Object p = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_PART_NAME); + if (s instanceof IStructuredSelection && p instanceof IWorkbenchPart) { + state = canEditRegisterGroup((IWorkbenchPart)p, (IStructuredSelection)s); + } + } + setBaseEnabled(state); + } + + @Override + public Object execute(ExecutionEvent event) { + ISelection selection = HandlerUtil.getCurrentSelection(event); + IWorkbenchPart part = HandlerUtil.getActivePart(event); + if (selection instanceof IStructuredSelection) { + editRegisterGroup(part, (IStructuredSelection)selection); + } + return null; + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfRemoveRegisterGroupsCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfRemoveRegisterGroupsCommand.java new file mode 100644 index 00000000000..42a02b5e454 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfRemoveRegisterGroupsCommand.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.internal.ui.actions; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISources; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Command performing adding a register group. + * @since 2.4 + */ +public class DsfRemoveRegisterGroupsCommand extends AbstractDsfRegisterGroupActions { + @Override + public void setEnabled(Object evaluationContext) { + boolean state = false; + if (evaluationContext instanceof IEvaluationContext) { + Object s = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); + Object p = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_PART_NAME); + if (s instanceof IStructuredSelection && p instanceof IWorkbenchPart) { + state = canRemoveRegisterGroups((IWorkbenchPart)p, (IStructuredSelection)s); + } + } + setBaseEnabled(state); + } + + @Override + public Object execute(ExecutionEvent event) { + ISelection selection = HandlerUtil.getCurrentSelection(event); + IWorkbenchPart part = HandlerUtil.getActivePart(event); + if (selection instanceof IStructuredSelection) { + removeRegisterGroups(part, (IStructuredSelection)selection); + } + return null; + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfRestoreRegisterGroupsCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfRestoreRegisterGroupsCommand.java new file mode 100644 index 00000000000..c8cc4e53bea --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/actions/DsfRestoreRegisterGroupsCommand.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.debug.internal.ui.actions; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.ISources; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Command performing adding a register group. + * @since 2.4 + */ +public class DsfRestoreRegisterGroupsCommand extends AbstractDsfRegisterGroupActions { + @Override + public void setEnabled(Object evaluationContext) { + boolean state = false; + if (evaluationContext instanceof IEvaluationContext) { + Object s = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_MENU_SELECTION_NAME); + Object p = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_PART_NAME); + if (s instanceof IStructuredSelection && p instanceof IWorkbenchPart) { + state = canRestoreDefaultGroups((IWorkbenchPart)p, (IStructuredSelection)s); + } + } + setBaseEnabled(state); + } + + @Override + public Object execute(ExecutionEvent event) { + ISelection selection = HandlerUtil.getCurrentSelection(event); + IWorkbenchPart part = HandlerUtil.getActivePart(event); + if (selection instanceof IStructuredSelection) { + restoreDefaultGroups(part, (IStructuredSelection)selection); + } + return null; + } +} diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/internal/ui/DsfUIPlugin.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/internal/ui/DsfUIPlugin.java index 81522fd21d0..a6e95a7b362 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/internal/ui/DsfUIPlugin.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/internal/ui/DsfUIPlugin.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems and others. + * Copyright (c) 2006, 2014 Wind River Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * Wind River Systems - initial API and implementation + * Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747) *******************************************************************************/ package org.eclipse.cdt.dsf.internal.ui; @@ -22,6 +23,8 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; @@ -168,5 +171,19 @@ public class DsfUIPlugin extends AbstractUIPlugin { public static IStatus newErrorStatus(int code, String message, Throwable exception) { return new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, code, message, exception); } + + /** + * Returns the active workbench shell or null if none + * + * @return the active workbench shell or null if none + */ + public static Shell getActiveWorkbenchShell() { + IWorkbenchWindow window = getDefault().getWorkbench().getActiveWorkbenchWindow(); + if (window != null) { + return window.getShell(); + } + + return null; + } } diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters2.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters2.java new file mode 100644 index 00000000000..6939580d867 --- /dev/null +++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters2.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2014 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Alvaro Sanchez-Leon (Ericsson) - First API (Bug 235747) + *******************************************************************************/ + +package org.eclipse.cdt.dsf.debug.service; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.IDMContext; + +/** + * Service extension of IRegisters to manage user defined Register Groups + * @since 2.6 + */ +public interface IRegisters2 extends IRegisters { + /** + * Returns a boolean indicating if it is allowed to add a new register group with the given selected context + * + * @param rm - monitor encapsulating the response + */ + public void canAddRegisterGroup(IDMContext ctx, DataRequestMonitor rm); + + /** + * Add a Register group referencing the given registers + * + * @param ctx - A context containing a parent group context e.g. IContainerDMContext + * @param name - register group name + * @param registers - registers part of this new group + * @param rm - request monitor + */ + public void addRegisterGroup(IDMContext ctx, String name, IRegisterDMContext[] registers, RequestMonitor rm); + + /** + * Returns a boolean indicating if it is allowed to edit the given group + * + * @param rm - monitor encapsulating the response + */ + public void canEditRegisterGroup(IRegisterGroupDMContext group, + DataRequestMonitor rm); + + /** + * Edit the given register group and update its name and associated registers + * + * @param group - group to be edited + * @param groupName - new group name or null if name is not to be changed + * @param registers - new list of registers for this group or null if the list of registers is not be changed + * @param rm - request monitor + */ + public void editRegisterGroup(IRegisterGroupDMContext group, String groupName, + IRegisterDMContext[] registers, RequestMonitor rm); + + /** + * Returns a boolean indicating if it is allowed to remove the given registers groups + * @param groups - list of register group contexts to be removed + * @param rm + */ + public void canRemoveRegisterGroups(IRegisterGroupDMContext[] groups, + DataRequestMonitor rm); + + /** + * Remove the given register groups + * + * @param groups - groups that shall be removed + * @param rm - request monitor + */ + public void removeRegisterGroups(IRegisterGroupDMContext[] groups, RequestMonitor rm); + + /** + * Returns a boolean indicating if it is allowed to restore to the default groups + * @param ctx + * @param rm + */ + public void canRestoreDefaultGroups(IDMContext ctx, DataRequestMonitor rm); + + /** + * Remove all the user defined register groups and restore the default ones to their + * original state. + * + * @param rm - request monitor + */ + public void restoreDefaultGroups(IDMContext selectionContext, RequestMonitor rm); + +}