diff options
author | Bruno Medeiros | 2017-01-19 17:14:24 +0000 |
---|---|---|
committer | Alvaro Sanchez-Leon | 2017-02-28 20:41:10 +0000 |
commit | 5a71bf21d82d2563b0d37d73a99977d5617c2788 (patch) | |
tree | 4b2c65d3e204a04a42cf5b97827e84d709f8832b | |
parent | 064ce187b6de00e343b26a614a98846ef46213d7 (diff) | |
download | org.eclipse.cdt-5a71bf21d82d2563b0d37d73a99977d5617c2788.tar.gz org.eclipse.cdt-5a71bf21d82d2563b0d37d73a99977d5617c2788.tar.xz org.eclipse.cdt-5a71bf21d82d2563b0d37d73a99977d5617c2788.zip |
Bug 449104: Enhance Register Grouping for multi processes
This patch adds support to GDBRegisters for persisting the register
group configuration on a per-process/per-core basis. The default
behavior of GDBRegisters is not modified. Instead, subclasses must
override getPersistenceIdForRegisterGroupContainer(IContainerDMContext)
to enable the new behavior, and provide a persistence id that is stable
across launches.
Update: fixed bug in RegisterGroupDescriptor.getContainerId()
Change-Id: I284df3ee215d9a4a9f72f3dca9aba5c16ca4b850
Signed-off-by: Bruno Medeiros <bruno.do.medeiros@gmail.com>
8 files changed, 435 insertions, 36 deletions
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 index ac3b737b0a8..55afb154c97 100644 --- 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 @@ -8,6 +8,7 @@ * 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 + * Bruno Medeiros (Renesas) - Persistence of register groups per process (449104) *******************************************************************************/ package org.eclipse.cdt.debug.internal.core; @@ -39,6 +40,7 @@ public class RegisterGroupsPersistance { 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_CONTAINER_ID = "parent_id"; //$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$ @@ -60,12 +62,17 @@ public class RegisterGroupsPersistance { private final String fMemento; private final String fName; private final boolean fEnabled; + private final String fContainerId; IRegisterDescriptor[] fRegisterDescriptors = null; - public RegisterGroupDescriptor(String memento, String groupName, boolean enabled) { + public RegisterGroupDescriptor(String memento, String groupName, boolean enabled, String containerId) { fMemento = memento; fName = groupName; fEnabled = enabled; + if (containerId != null && containerId.length() == 0) { + containerId = null; + } + fContainerId = containerId; } @Override @@ -77,6 +84,11 @@ public class RegisterGroupsPersistance { public boolean isEnabled() { return fEnabled; } + + @Override + public String getContainerId() { + return fContainerId; + } @Override public IRegisterDescriptor[] getChildren() throws CoreException { @@ -144,11 +156,16 @@ public class RegisterGroupsPersistance { return fLaunchConfigTargetAttribute; } - - public IRegisterGroupDescriptor[] parseGroups() { + + /** + * Parse register groups. + * If given containerId is not null, the only returned register groups are the one + * whose container id matches given containerId + */ + public IRegisterGroupDescriptor[] parseGroups(String containerId) throws CoreException { List<IRegisterGroupDescriptor> groups = new ArrayList<IRegisterGroupDescriptor>(); String memento; - try { + memento = fLaunchConfig.getAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_REGISTER_GROUPS, BLANK_STRING); if (memento != null && memento.length() > 0) { @@ -168,10 +185,12 @@ public class RegisterGroupsPersistance { 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); + if(containerId == null || containerId.equals(groupdesc.getContainerId())) { + groups.add(groupdesc); + } } } } @@ -179,10 +198,6 @@ public class RegisterGroupsPersistance { } } - } catch (CoreException e) { - - e.printStackTrace(); - } return groups.toArray(new IRegisterGroupDescriptor[groups.size()]); @@ -217,12 +232,11 @@ public class RegisterGroupsPersistance { if (groupName == null || groupName.length() == 0) { abort(CoreModelMessages.getString("CRegisterGroup.2"), null); //$NON-NLS-1$ } + String containerId = element.getAttribute(ATTR_REGISTER_CONTAINER_ID); String e = element.getAttribute(ATTR_REGISTER_GROUP_ENABLED); boolean enabled = Boolean.parseBoolean(e); - IRegisterGroupDescriptor group = new RegisterGroupDescriptor(memento, groupName, enabled); - - return group; + return new RegisterGroupDescriptor(memento, groupName, enabled, containerId); } private String getMemento(IRegisterGroupDescriptor[] groups) throws CoreException { @@ -243,6 +257,7 @@ public class RegisterGroupsPersistance { Element element = document.createElement(ELEMENT_REGISTER_GROUP); element.setAttribute(ATTR_REGISTER_GROUP_NAME, group.getName()); element.setAttribute(ATTR_REGISTER_GROUP_ENABLED, String.valueOf(group.isEnabled())); + element.setAttribute(ATTR_REGISTER_CONTAINER_ID, group.getContainerId()); IRegisterDescriptor[] registerDescriptors = group.getChildren(); for (int i = 0; i < registerDescriptors.length; ++i) { Element child = document.createElement(ELEMENT_REGISTER); 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 index ff72c97a26b..83a80a6b794 100644 --- 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 @@ -32,4 +32,13 @@ public interface IRegisterGroupDescriptor { * @throws CoreException */ public IRegisterDescriptor[] getChildren() throws CoreException; + + /** + * The id of the container this register group belongs to. + * If null, the register group applies to the entire launch, + * otherwise it applies only to a given core, or process, within the launch. + */ + default String getContainerId() { + return null; + }; } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/.settings/org.eclipse.jdt.core.prefs b/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/.settings/org.eclipse.jdt.core.prefs index ce1f6109477..87965802f37 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/.settings/org.eclipse.jdt.core.prefs +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/.settings/org.eclipse.jdt.core.prefs @@ -60,7 +60,7 @@ org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverridin org.eclipse.jdt.core.compiler.problem.unusedImport=error org.eclipse.jdt.core.compiler.problem.unusedLabel=warning org.eclipse.jdt.core.compiler.problem.unusedLocal=warning -org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=warning org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/service/CommonDsfTest.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/service/CommonDsfTest.java new file mode 100644 index 00000000000..094bcb18f75 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/service/CommonDsfTest.java @@ -0,0 +1,109 @@ +/*******************************************************************************
+ * Copyright (c) 2017 Renesas Electronics 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:
+ * Bruno Medeiros (Renesas) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.service;
+
+import static org.junit.Assert.fail;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.model.DsfLaunch;
+import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+/**
+ * Helper base class for running DSF related tests
+ */
+public class CommonDsfTest extends CommonTest {
+
+ protected static DsfSession fSession = null;
+
+ /**
+ * Setup the test.
+ * The session is typically configured once per class load, but we allow subclasses to override this,
+ * and sometimes re-setup during a test (or interactive debugging).
+ * Therefore {@link Before} is used, not {@link BeforeClass}.
+ */
+ @Before
+ public void setup() {
+ if(fSession != null) {
+ return; // Already set-up
+ }
+
+ doSetupSession();
+ }
+
+ protected void doSetupSession() {
+ fSession = DsfSession.startSession(new DefaultDsfExecutor(GdbPlugin.PLUGIN_ID), GdbPlugin.PLUGIN_ID);
+
+ registerLaunch();
+ }
+
+ @AfterClass
+ public static void tearDown() {
+ if(fSession != null) {
+ DsfSession.endSession(fSession);
+ fSession = null;
+ }
+ }
+
+ protected ILaunchConfigurationType getCLaunchConfigType() {
+ return getLaunchManager().getLaunchConfigurationType(ICDTLaunchConfigurationConstants.ID_LAUNCH_C_APP);
+ }
+
+ protected ILaunchManager getLaunchManager() {
+ return DebugPlugin.getDefault().getLaunchManager();
+ }
+
+ protected void registerLaunch() {
+ ILaunchConfigurationWorkingCopy lc;
+ try {
+ lc = getCLaunchConfigType().newInstance(null, "TestLaunch");
+ } catch(CoreException e) {
+ fail(e.getMessage());
+ return;
+ }
+ ISourceLocator sourceLocator = null;
+ DsfLaunch dsfLaunch = new DsfLaunch(lc, ILaunchManager.DEBUG_MODE, sourceLocator);
+ fSession.registerModelAdapter(ILaunch.class, dsfLaunch);
+ }
+
+ protected RequestMonitor newRequestMonitor() {
+ return new RequestMonitor(fSession.getExecutor(), null);
+ }
+
+ protected <T> DataRequestMonitor<T> newDataRequestMonitor() {
+ return new DataRequestMonitor<>(fSession.getExecutor(), null);
+ }
+}
+
+/**
+ * Misc test utilities.
+ */
+class CommonTest {
+ /* ----------------- ----------------- */
+
+ @SafeVarargs
+ public static <T> T[] array(T... elems) {
+ return elems;
+ }
+}
\ No newline at end of file diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisterTest.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisterTest.java new file mode 100644 index 00000000000..eb22e775d3d --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisterTest.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2017 Renesas Electronics 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: + * Bruno Medeiros (Renesas) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.service; + +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + +import org.eclipse.cdt.debug.internal.core.model.IRegisterGroupDescriptor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; +import org.eclipse.cdt.dsf.mi.service.MIProcesses; +import org.eclipse.cdt.dsf.mi.service.MIRegisters.MIRegisterDMC; +import org.eclipse.cdt.dsf.mi.service.MIRegisters.MIRegisterGroupDMC; +import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext; +import org.eclipse.core.runtime.Assert; +import org.junit.Test; + + +public class GDBRegisterTest extends CommonDsfTest { + + public static final String PROCESS_A = "processA"; + public static final String PROCESS_B = "processB"; + + protected MIProcesses miProcesses; + protected GDBRegisters gdbRegisters; + + @Override + protected void doSetupSession() { + super.doSetupSession(); + + miProcesses = new MIProcesses(fSession); + gdbRegisters = createGdbRegisters(); + } + + protected GDBRegisters createGdbRegisters() { + return new GDBRegisters(fSession) { + @Override + protected boolean useProcessIdAsRegisterGroupPersistanceId() { + return true; + } + }; + } + + @Test + public void testRegisterPersistence() throws Exception { testRegisterPersistence$(); } + public void testRegisterPersistence$() throws Exception { + + MIControlDMContext controlDmc = new MIControlDMContext(fSession.getId(), "TestControl"); + + IProcessDMContext processDmcA = miProcesses.createProcessContext(controlDmc, PROCESS_A); + IProcessDMContext processDmcB = miProcesses.createProcessContext(controlDmc, PROCESS_B); + IMIContainerDMContext containerA = miProcesses.createContainerContext(processDmcA, "containerA"); + IMIContainerDMContext containerB = miProcesses.createContainerContext(processDmcB, "containerB"); + + + MIRegisterGroupDMC[] initialRegisterGroups = gdbRegisters.readGroupsFromMemento(containerA); + Assert.isTrue(initialRegisterGroups.length == 0); + + MIRegisterGroupDMC registerGroupA = addRegisterGroup(containerA, "RegGroupA", "register_foo"); + // check build descriptors + IRegisterGroupDescriptor[] buildDescriptors = gdbRegisters.buildDescriptors(); + org.junit.Assert.assertEquals(buildDescriptors[0].getContainerId(), gdbRegisters.getPersistenceIdForRegisterGroupContainer(containerA)); + + // Save then check persistence + gdbRegisters.save(); + checkAfterAdding_GroupA(containerA, containerB, registerGroupA); + + // Now add a second register group to a different process context + MIRegisterGroupDMC registerGroupB = addRegisterGroup(containerB, "RegGroupB", "register_bar"); + gdbRegisters.save(); + checkAfterAdding_GroupB(containerA, containerB, registerGroupA, registerGroupB); + } + + protected void checkAfterAdding_GroupA( + IMIContainerDMContext containerA, IMIContainerDMContext containerB, MIRegisterGroupDMC registerGroupA + ) { + checkRegisterGroupMemento(containerA, registerGroupA); + checkRegisterGroupsMemento(containerB, array()); + } + + protected void checkAfterAdding_GroupB( + IMIContainerDMContext containerA, IMIContainerDMContext containerB, + MIRegisterGroupDMC registerGroupA, MIRegisterGroupDMC registerGroupB + ) { + checkRegisterGroupMemento(containerA, registerGroupA); + checkRegisterGroupMemento(containerB, registerGroupB); + } + + protected MIRegisterGroupDMC addRegisterGroup(IMIContainerDMContext container, String groupName, String registerName) { + MIRegisterGroupDMC registerGroup = new MIRegisterGroupDMC(gdbRegisters, container, 1, groupName); + MIRegisterDMC rgFoo = new MIRegisterDMC(gdbRegisters, registerGroup, 1, registerName); + + gdbRegisters.addRegisterGroup(container, registerGroup.getName(), array(rgFoo), newRequestMonitor()); + return registerGroup; + } + + protected void checkRegisterGroupMemento(IMIContainerDMContext container, MIRegisterGroupDMC registerGroup) { + checkRegisterGroupsMemento(container, array(registerGroup)); + } + + protected void checkRegisterGroupsMemento(IMIContainerDMContext container, MIRegisterGroupDMC[] expectedRegisterGroups) { + MIRegisterGroupDMC[] savedRegisterGroups = gdbRegisters.readGroupsFromMemento(container); + if(expectedRegisterGroups == null) { + assertTrue(savedRegisterGroups == null); + return; + } + + assertTrue(expectedRegisterGroups.length == savedRegisterGroups.length); + + for (int ix = 0; ix < expectedRegisterGroups.length; ix++) { + MIRegisterGroupDMC expectedRG = expectedRegisterGroups[ix]; + int groupNo = savedRegisterGroups[ix].getGroupNo(); // Don't check group number, so set expected to obtained value + expectedRegisterGroups[ix] = new MIRegisterGroupDMC(gdbRegisters, container, groupNo, expectedRG.getName()); + } + + assertTrue(Arrays.equals(expectedRegisterGroups, savedRegisterGroups)); + } + + /* ----------------- ----------------- */ + + /** + * Variant of {@link GDBRegisterTest} where register groups are saved without a container id. + * This is the default behavior for register group persistence. + */ + public static class GDBRegisterTest_NoContainerTest extends GDBRegisterTest { + + @Override + protected GDBRegisters createGdbRegisters() { + return new GDBRegisters(fSession) { + @Override + protected boolean useProcessIdAsRegisterGroupPersistanceId() { + return false; + } + }; + } + + @Override + protected void checkAfterAdding_GroupA( + IMIContainerDMContext containerA, IMIContainerDMContext containerB, MIRegisterGroupDMC registerGroupA + ) { + checkRegisterGroupMemento(containerA, registerGroupA); + checkRegisterGroupMemento(containerB, registerGroupA); + } + + @Override + protected void checkAfterAdding_GroupB( + IMIContainerDMContext containerA, IMIContainerDMContext containerB, + MIRegisterGroupDMC registerGroupA, MIRegisterGroupDMC registerGroupB + ) { + checkRegisterGroupsMemento(containerA, array(registerGroupA, registerGroupB)); + checkRegisterGroupsMemento(containerB, array(registerGroupA, registerGroupB)); + } + } + + public static class GDBRegisterTest_WithAlternativeProcessIdTest extends GDBRegisterTest { + + @Override + protected GDBRegisters createGdbRegisters() { + return new GDBRegisters(fSession) { + @Override + protected boolean useProcessIdAsRegisterGroupPersistanceId() { + return true; + } + @Override + protected String getPersistenceIdForRegisterGroupContainer(IContainerDMContext contDmc) { + return super.getPersistenceIdForRegisterGroupContainer(contDmc) + "XXX"; + } + }; + } + + } + + + public static class GDBRegisterTest_WithContainerDMContextTest extends GDBRegisterTest { + + @Override + protected GDBRegisters createGdbRegisters() { + return new GDBRegisters(fSession) { + @Override + protected String getPersistenceIdForRegisterGroupContainer(IContainerDMContext contDmc) { + IMIContainerDMContext contextDmc = DMContexts.getAncestorOfType(contDmc, IMIContainerDMContext.class); + return contextDmc.getGroupId(); + } + }; + } + + } +}
\ No newline at end of file diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/tests/AutomatedIntegrationSuite.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/tests/AutomatedIntegrationSuite.java index 37eb0477a83..2ab2a2e0c41 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/tests/AutomatedIntegrationSuite.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/tests/AutomatedIntegrationSuite.java @@ -10,6 +10,10 @@ *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.tests; +import org.eclipse.cdt.dsf.gdb.service.GDBRegisterTest; +import org.eclipse.cdt.dsf.gdb.service.GDBRegisterTest.GDBRegisterTest_NoContainerTest; +import org.eclipse.cdt.dsf.gdb.service.GDBRegisterTest.GDBRegisterTest_WithAlternativeProcessIdTest; +import org.eclipse.cdt.dsf.gdb.service.GDBRegisterTest.GDBRegisterTest_WithContainerDMContextTest; import org.eclipse.cdt.dsf.mi.service.command.commands.TestMIBreakInsertCommand; import org.eclipse.cdt.dsf.mi.service.command.commands.TestMICommandConstructCommand; import org.eclipse.cdt.dsf.mi.service.command.commands.TestMIGDBSetSysroot; @@ -30,6 +34,10 @@ import org.junit.runners.Suite.SuiteClasses; MIStringHandlerTests.class, ProcStatParserTest.class, FilePartsTest.class, + GDBRegisterTest.class, + GDBRegisterTest_NoContainerTest.class, + GDBRegisterTest_WithAlternativeProcessIdTest.class, + GDBRegisterTest_WithContainerDMContextTest.class, }) public class AutomatedIntegrationSuite { // Often overriding BeforeClass method here 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 index d9bda88cb36..537fdbb23d3 100644 --- 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 @@ -7,6 +7,7 @@ * * Contributors: * Alvaro Sanchez-Leon (Ericsson) - First Implementation and API (Bug 235747) + * Bruno Medeiros (Renesas) - Persistence of register groups per process (449104) *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; @@ -15,7 +16,6 @@ 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; @@ -40,6 +40,7 @@ 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.IMIProcessDMContext; import org.eclipse.cdt.dsf.mi.service.MIRegisters; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.CoreException; @@ -52,7 +53,9 @@ 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> + * <p>This class also triggers the read/write (persistence) of the user-defined Register Groups during the start/shutdown process of a session respectively. + * It optionally supports persistence of user-defined Register Groups per container/process, + * see {@link #getPersistenceIdForRegisterGroupContainer(IContainerDMContext)}.</p> * @since 4.6 */ public class GDBRegisters extends MIRegisters implements IRegisters2 { @@ -239,6 +242,12 @@ public class GDBRegisters extends MIRegisters implements IRegisters2 { public boolean isEnabled() { return fEnabled; } + + @Override + public String getContainerId() { + IContainerDMContext parent = fgroup.getContainerParent(); + return getPersistenceIdForRegisterGroupContainer(parent); + } @Override public IRegisterDescriptor[] getChildren() throws CoreException { @@ -520,9 +529,6 @@ public class GDBRegisters extends MIRegisters implements IRegisters2 { } } - // 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( @@ -727,17 +733,21 @@ public class GDBRegisters extends MIRegisters implements IRegisters2 { super.shutdown(rm); } + /** + * Save the register group settings into the underlying launch configuration. + */ 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(); - } - } + IRegisterGroupDescriptor[] groups = buildDescriptors(); + ILaunchConfiguration launchConfig = getLaunchConfig(); + if (launchConfig != null) { + RegisterGroupsPersistance serializer = new RegisterGroupsPersistance(launchConfig); + try { + serializer.saveGroups(groups); + } catch (CoreException e) { + GdbPlugin.log(e); + } + } + } /** @@ -855,7 +865,7 @@ public class GDBRegisters extends MIRegisters implements IRegisters2 { return config; } - private IRegisterGroupDescriptor[] buildDescriptors() { + IRegisterGroupDescriptor[] buildDescriptors() { // use a tree map to sort the entries by group number TreeMap<Integer, MIRegisterGroupDMC> sortedGroups = new TreeMap<Integer, MIRegisterGroupDMC>(); @@ -872,9 +882,8 @@ public class GDBRegisters extends MIRegisters implements IRegisters2 { // 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); + for (Entry<Integer, MIRegisterGroupDMC> groupEntry : groupSet) { + descriptors[i] = new RegisterGroupDescriptor(groupEntry.getValue(), true); i++; } @@ -895,9 +904,16 @@ public class GDBRegisters extends MIRegisters implements IRegisters2 { return newArr; } - private MIRegisterGroupDMC[] readGroupsFromMemento(final IContainerDMContext contDmc) { + MIRegisterGroupDMC[] readGroupsFromMemento(final IContainerDMContext contDmc) { + String containerId = getPersistenceIdForRegisterGroupContainer(contDmc); + RegisterGroupsPersistance deserializer = new RegisterGroupsPersistance(getLaunchConfig()); - IRegisterGroupDescriptor[] groupDescriptions = deserializer.parseGroups(); + IRegisterGroupDescriptor[] groupDescriptions; + try { + groupDescriptions = deserializer.parseGroups(containerId); + } catch(CoreException e) { + return new MIRegisterGroupDMC[0]; + } List<MIRegisterGroupDMC> groups = new ArrayList<MIRegisterGroupDMC>(); for (IRegisterGroupDescriptor group : groupDescriptions) { @@ -908,6 +924,39 @@ public class GDBRegisters extends MIRegisters implements IRegisters2 { return groups.toArray(new MIRegisterGroupDMC[groups.size()]); } + + /** + * @return the persistence id for the register group in the given contDmc container context, + * or null to associate the Register Groups in the given container to the launch itself (this is the default behavior). + * + * Subclasses may override. Alternatively simply use override {@link #useProcessIdAsRegisterGroupPersistanceId()} to return true to have + * the process id be used as the persistence id. + * + * Note that for this to work correctly the id returned for a given container must be same across launch sessions, + * otherwise persistence info will be lost. (Hence why null is the default behavior) + * + * @since 5.3 + */ + protected String getPersistenceIdForRegisterGroupContainer(final IContainerDMContext contDmc) { + if(useProcessIdAsRegisterGroupPersistanceId()) { + IMIProcessDMContext processDmc = DMContexts.getAncestorOfType(contDmc, IMIProcessDMContext.class); + return processDmc == null ? null : processDmc.getProcId(); + } else { + return null; + } + } + + /** + * @return whether the process id should be used as a container id for the persistence + * of the register groups. Subclasses may override. + * + * @see #getPersistenceIdForRegisterGroupContainer(IContainerDMContext) + * + * @since 5.3 + */ + protected boolean useProcessIdAsRegisterGroupPersistanceId() { + return false; + } private void getUserGroupRegisters(IDMContext ctx, final DataRequestMonitor<IRegisterDMContext[]> rm) { final MIRegisterGroupDMC groupDmc = DMContexts.getAncestorOfType(ctx, MIRegisterGroupDMC.class); 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 94b9b865bf3..27154be2e66 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 @@ -85,17 +85,27 @@ public class MIRegisters extends AbstractDsfService implements IRegisters, ICach */ public static class MIRegisterGroupDMC extends AbstractDMContext implements IRegisterGroupDMContext { - private int fGroupNo; + private final int fGroupNo; + private final IContainerDMContext parent; private String fGroupName; public MIRegisterGroupDMC(MIRegisters service, IContainerDMContext contDmc, int groupNo, String groupName) { super(service.getSession().getId(), new IDMContext[] { contDmc }); + this.parent = contDmc; fGroupNo = groupNo; fGroupName = groupName; } public int getGroupNo() { return fGroupNo; } public String getName() { return fGroupName; } + + /** + * @since 5.3 + */ + public IContainerDMContext getContainerParent() { + return parent; + } + /** * @since 4.6 */ |