mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
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>
This commit is contained in:
parent
064ce187b6
commit
5a71bf21d8
8 changed files with 435 additions and 36 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue