From 5a71bf21d82d2563b0d37d73a99977d5617c2788 Mon Sep 17 00:00:00 2001 From: Bruno Medeiros Date: Thu, 19 Jan 2017 17:14:24 +0000 Subject: [PATCH] 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 --- .../core/RegisterGroupsPersistance.java | 41 ++-- .../core/model/IRegisterGroupDescriptor.java | 9 + .../.settings/org.eclipse.jdt.core.prefs | 2 +- .../cdt/dsf/gdb/service/CommonDsfTest.java | 109 ++++++++++ .../cdt/dsf/gdb/service/GDBRegisterTest.java | 199 ++++++++++++++++++ .../gdb/tests/AutomatedIntegrationSuite.java | 8 + .../cdt/dsf/gdb/service/GDBRegisters.java | 91 ++++++-- .../cdt/dsf/mi/service/MIRegisters.java | 12 +- 8 files changed, 435 insertions(+), 36 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/service/CommonDsfTest.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.tests/src/org/eclipse/cdt/dsf/gdb/service/GDBRegisterTest.java 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 groups = new ArrayList(); 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 DataRequestMonitor newDataRequestMonitor() { + return new DataRequestMonitor<>(fSession.getExecutor(), null); + } +} + +/** + * Misc test utilities. + */ +class CommonTest { + /* ----------------- ----------------- */ + + @SafeVarargs + public static 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; /** *

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

*

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

- *

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

+ *

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)}.

* @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 sortedGroups = new TreeMap(); @@ -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> iterator = groupSet.iterator(); iterator.hasNext();) { - Entry entry = iterator.next(); - descriptors[i] = new RegisterGroupDescriptor(entry.getValue(), true); + for (Entry 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 groups = new ArrayList(); 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 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 */