Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlvaro Sanchez-Leon2014-10-24 15:42:04 +0000
committerAlvaro Sanchez-Leon2014-12-09 15:37:26 +0000
commit3ab1678bc370c56cb41f6830a872e806555ef61a (patch)
tree18157c35fbde11d23a71f0947d8dd8ced5337caf /dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse
parenta830f285fe92a58fb9689020c3ddc605b0d36867 (diff)
downloadorg.eclipse.cdt-3ab1678bc370c56cb41f6830a872e806555ef61a.tar.gz
org.eclipse.cdt-3ab1678bc370c56cb41f6830a872e806555ef61a.tar.xz
org.eclipse.cdt-3ab1678bc370c56cb41f6830a872e806555ef61a.zip
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 <alvsan09@gmail.com> Signed-off-by: Marc Khouzam <marc.khouzam@ericsson.com> Reviewed-on: https://git.eclipse.org/r/13980 Tested-by: Hudson CI
Diffstat (limited to 'dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse')
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBPatternMatchingExpressions.java62
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisters.java1137
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java4
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.java6
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/Messages.properties6
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRegisters.java176
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.java5
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/Messages.properties7
8 files changed, 1294 insertions, 109 deletions
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<List<IExpressionDMContext>> 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<IRegisterGroupDMContext[]>(rm) {
- @Override
- protected void handleSuccess() {
- registerService.getRegisters(
- new CompositeDMContext(new IDMContext[] { getData()[0], globDmc } ),
- new ImmediateDataRequestMonitor<IRegisterDMContext[]>(rm) {
- @Override
- protected void handleSuccess() {
- assert getData() instanceof MIRegisterDMC[];
- ArrayList<IExpressionDMContext> matches = new ArrayList<IExpressionDMContext>();
-
- 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<IRegisterDMContext[]>(rm) {
+ @Override
+ protected void handleSuccess() {
+ assert getData() instanceof MIRegisterDMC[];
+ ArrayList<IExpressionDMContext> matches = new ArrayList<IExpressionDMContext>();
+
+ 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;
+
+/**
+ * <p>An extension of MIRegisters to support management of Register Groups as per the IRegisters2 interface.</p>
+ * <p>The managed registered groups are user-defined subsets of the complete list of Registers reported by GDB for a specific Target</p>
+ * <p>This class also triggers the read/write (persistence) of the user-defined Register Groups during the start/shutdown process of a session respectively</p>
+ * @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<IContainerDMContext, MIRegisterGroupDMC[]> fContextToGroupsMap = new ContextToGroupsMap<IContainerDMContext, MIRegisterGroupDMC[]>();
+
+ /**
+ * 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<MIRegisterGroupDMC, MIRegisterDMC[]> fGroupToRegistersMap = new GroupRegistersMap<MIRegisterGroupDMC, MIRegisterDMC[]>();
+
+ /**
+ * 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<Integer, IRegisterGroupDescriptor> fGroupMementoDescriptorIndex = new HashMap<Integer, IRegisterGroupDescriptor>();
+
+ public GDBRegisters(DsfSession session) {
+ super(session);
+ }
+
+ private class ContextToGroupsMap<K, V> extends HashMap<IContainerDMContext, MIRegisterGroupDMC[]> {
+ private static final long serialVersionUID = 1L;
+ private final Map<IContainerDMContext, Map<String, MIRegisterGroupDMC>> fNameToGroupMap = new HashMap<IContainerDMContext, Map<String, MIRegisterGroupDMC>>();
+
+ @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<String, MIRegisterGroupDMC> getGroupNameMap(IContainerDMContext key) {
+ // validate input
+ if (key == null) {
+ return null;
+ }
+
+ Map<String, MIRegisterGroupDMC> nameMap = fNameToGroupMap.get(key);
+ if (nameMap == null) {
+ // cache not resolved, rebuild
+ nameMap = new HashMap<String, MIRegisterGroupDMC>();
+ 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<String,
+ * Register>)
+ */
+ private class GroupRegistersMap<K, V> extends HashMap<MIRegisterGroupDMC, MIRegisterDMC[]> {
+ private static final long serialVersionUID = 1L;
+ private final Map<MIRegisterGroupDMC, Map<String, MIRegisterDMC>> fNameToRegisterMap = new HashMap<MIRegisterGroupDMC, Map<String, MIRegisterDMC>>();
+
+ @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<String, MIRegisterDMC> getIndexedRegisters(MIRegisterGroupDMC key) {
+ Map<String, MIRegisterDMC> 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<String, MIRegisterDMC> indexRegisters(MIRegisterGroupDMC registerGroup) {
+ MIRegisterDMC[] registers = super.get(registerGroup);
+ if (registers == null || registers.length < 1) {
+ return null;
+ }
+
+ Map<String, MIRegisterDMC> registerNameMap = new HashMap<String, MIRegisterDMC>();
+ 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<String,String>());
+ requestMonitor.done();
+ }
+
+ @Override
+ public void getRegisterGroups(final IDMContext ctx, final DataRequestMonitor<IRegisterGroupDMContext[]> 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<IRegisterGroupDMContext[]>(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<IRegisterGroupDMData> 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<IRegisterDMContext[]> rm) {
+ findRegisterGroup(aCtx, ROOT_GROUP_NAME, new ImmediateDataRequestMonitor<IRegisterGroupDMContext>() {
+ @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<IRegisterDMContext[]>(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<Boolean> 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<Boolean> 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<IRegisterGroupDMContext> 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<IRegisterGroupDMContext[]>(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<IRegisterGroupDMContext> rm) {
+ Map<String, MIRegisterGroupDMC> 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<Integer, MIRegisterDMC> sortedRegisters = new TreeMap<Integer, MIRegisterDMC>();
+ 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<IContainerDMContext> updatedContainers = new HashSet<IContainerDMContext>();
+ 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<MIRegisterGroupDMC> groupsList = new ArrayList<MIRegisterGroupDMC>(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<Integer, MIRegisterGroupDMC> sortedGroups = new TreeMap<Integer, MIRegisterGroupDMC>();
+
+ 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<Entry<Integer, MIRegisterGroupDMC>> 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<Entry<Integer, MIRegisterGroupDMC>> iterator = groupSet.iterator(); iterator.hasNext();) {
+ Entry<Integer, MIRegisterGroupDMC> entry = iterator.next();
+ descriptors[i] = new RegisterGroupDescriptor(entry.getValue(), true);
+ i++;
+ }
+
+ return descriptors;
+ }
+
+ private <T> 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<MIRegisterGroupDMC> groups = new ArrayList<MIRegisterGroupDMC>();
+ 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<IRegisterDMContext[]> 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<MIRegisterDMC> registerContexts = new ArrayList<MIRegisterDMC>();
+ 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<String, MIRegisterDMC> 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<IRegisterDMContext[]> 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<IStack.IFrameDMContext>(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<IRegisterDMContext[]> 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<Boolean> 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<Boolean> 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<IContainerDMContext, MIRegisterGroupDMC> fContainerToGroupMap = new HashMap<IContainerDMContext, MIRegisterGroupDMC>();
+
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<IRegisterGroupDMData> 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$
-
- final FormattedValueDMContext valueDmc = exprService.getFormattedValueContext(exprCtxt, formatId);
- exprService.getFormattedExpressionValue(
- valueDmc,
- new DataRequestMonitor<FormattedValueDMData>(getExecutor(), rm) {
- @Override
- protected void handleSuccess() {
- if(! regValue.equals(getData().getFormattedValue()) || ! valueDmc.getFormatID().equals(formatId)){
- exprService.writeExpression(exprCtxt, regValue, formatId, new DataRequestMonitor<MIInfo>(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();
- }
- }
+ public void writeRegister(IRegisterDMContext regCtx, final String regValue, final String formatId,
+ final RequestMonitor rm) {
+
+ 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<FormattedValueDMData>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ if (!regValue.equals(getData().getFormattedValue()) || !valueDmc.getFormatID().equals(formatId)) {
+ exprService.writeExpression(exprCtxt, regValue, formatId, new DataRequestMonitor<MIInfo>(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

Back to the top