From 9537e51cf39f655d106d4b5a5ecf99c6d0844e92 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Sun, 11 Mar 2018 19:28:58 +0000 Subject: [PATCH] Bug 532297: Cache registers per version of GDB Change-Id: I2da702830f01035b99dc61fcdfb9e7a43fcc8d55 --- .../cdt/tests/dsf/gdb/framework/SyncUtil.java | 54 ++++++++++++++ .../GDBPatternMatchingExpressionsTest.java | 70 ++++--------------- .../tests/dsf/gdb/tests/MIRegistersTest.java | 58 ++------------- 3 files changed, 74 insertions(+), 108 deletions(-) diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java index 4c441f15c37..b87d79429a2 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java @@ -16,13 +16,16 @@ package org.eclipse.cdt.tests.dsf.gdb.framework; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.nio.ByteOrder; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -74,6 +77,7 @@ import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; +import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterNamesInfo; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil.DefaultTimeouts.ETimeout; @@ -100,11 +104,18 @@ public class SyncUtil { private static ISourceLookup fSourceLookup; + // Static list of register names as obtained directly from GDB. + // We make it static, key'ed on each version of gdb, so it does not + // get re-set for every test. + // Each version of GDB can expose the set of register differently + private static Map> fRegisterNames = new HashMap<>(); + // Initialize some common things, once the session has been established public static void initialize(DsfSession session) throws Exception { fSession = session; Runnable runnable = new Runnable() { + @Override public void run() { DsfServicesTracker tracker = new DsfServicesTracker( @@ -857,6 +868,49 @@ public class SyncUtil { return result; } + /** + * Get the registers directly from GDB (without using the registers service) + * @param gdbVersion + * @param context + * @return + * @throws Throwable + */ + public static List getRegistersFromGdb(String gdbVersion, IDMContext context) throws Throwable { + if (!fRegisterNames.containsKey(gdbVersion)) { + // The tests must run on different machines, so the set of registers can change. + // To deal with this we ask GDB for the list of registers. + // Note that we send an MI Command in this code and do not use the IRegister service; + // this is because we want to test the service later, comparing it to what we find + // by asking GDB directly. + Query query = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(context, IContainerDMContext.class); + fGdbControl.queueCommand( + fGdbControl.getCommandFactory().createMIDataListRegisterNames(containerDmc), rm); + } + }; + fSession.getExecutor().execute(query); + + MIDataListRegisterNamesInfo data = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); + String[] names = data.getRegisterNames(); + + // Remove registers with empty names since the service also + // remove them. I don't know why GDB returns such empty names. + List registerNames = new LinkedList(); + for (String name : names) { + if (!name.isEmpty()) { + registerNames.add(name); + } + } + assertNotEquals( + "Test does not make sense, and has probably completely failed, as there are no register names", + Collections.emptyList(), registerNames); + fRegisterNames.put(gdbVersion, registerNames); + } + return fRegisterNames.get(gdbVersion); + } + /** * Read data from memory. * diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/GDBPatternMatchingExpressionsTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/GDBPatternMatchingExpressionsTest.java index 6fe8014a6d7..ab7e2d3a692 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/GDBPatternMatchingExpressionsTest.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/GDBPatternMatchingExpressionsTest.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; @@ -37,22 +38,18 @@ import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContex import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext; import org.eclipse.cdt.dsf.debug.service.IRegisters2; -import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.mi.service.ClassAccessor.MIExpressionDMCAccessor; -import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExpressions; import org.eclipse.cdt.dsf.mi.service.MIRegisters.MIRegisterDMC; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; -import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterNamesInfo; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase; import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil; import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -106,53 +103,12 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase //************************************************************************************** // Utility methods //************************************************************************************** - - // Static list of register names as obtained directly from GDB. - // We make it static so it does not get re-set for every test - protected static List fRegisterNames = null; - - @BeforeClass - public static void initializeGlobals() { - // In case we run multiple GDB versions of this test - // in the same suite, we need to re-initialize the registers - // as they may change between GDB versions. - fRegisterNames = null; - } - - protected List get_X86_REGS() throws Throwable { - - if (fRegisterNames == null) { - // The tests must run on different machines, so the set of registers can change. - // To deal with this we ask GDB for the list of registers. - // Note that we send an MI Command in this code and do not use the IRegister service; - // this is because we want to test the service later, comparing it to what we find - // by asking GDB directly. - final IContainerDMContext container = SyncUtil.getContainerContext(); - Query query = new Query() { - @Override - protected void execute(DataRequestMonitor rm) { - IMICommandControl controlService = fServicesTracker.getService(IMICommandControl.class); - controlService.queueCommand( - controlService.getCommandFactory().createMIDataListRegisterNames(container), rm); - } - }; - fSession.getExecutor().execute(query); - - MIDataListRegisterNamesInfo data = query.get(); - String[] names = data.getRegisterNames(); - - // Remove registers with empty names since the service also - // remove them. I don't know why GDB returns such empty names. - fRegisterNames = new LinkedList(); - for (String name : names) { - if (!name.isEmpty()) { - // Add the '$' prefix - fRegisterNames.add("$"+name); - } - } - } - // Return a copy since it will be modified by each test - return new LinkedList(fRegisterNames); + /** + * Return a new, mutable list with '$' prefixed on each register + */ + protected List getRegistersFromGdb() throws Throwable { + List registersFromGdb = SyncUtil.getRegistersFromGdb(getGdbVersion(), SyncUtil.getContainerContext()); + return registersFromGdb.stream().map(n -> "$" + n).collect(Collectors.toCollection(LinkedList::new)); } final static String[] fAllVariables = new String[] { "firstarg", "firstvar", "ptrvar", "secondarg", "secondvar", "var", "var2" }; @@ -343,7 +299,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase public void testMatchAllRegs() throws Throwable { final String exprString = "$*"; final String exprString2 = "=$*"; - List regList = get_X86_REGS(); + List regList = getRegistersFromGdb(); Collections.sort(regList); final String[] children = regList.toArray(new String[0]); @@ -1060,7 +1016,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase @Test public void testGroupAllRegsAllLocals() throws Throwable { final String exprString = "$*; *"; - List list = get_X86_REGS(); + List list = getRegistersFromGdb(); Collections.sort(list); list.addAll(Arrays.asList(fAllVariables)); final String[] children = list.toArray(new String[list.size()]); @@ -1083,7 +1039,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase @Test public void testGroupAllLocalsAllRegs() throws Throwable { final String exprString = "*; $*"; - List list = get_X86_REGS(); + List list = getRegistersFromGdb(); Collections.sort(list); list.addAll(0, Arrays.asList(fAllVariables)); final String[] children = list.toArray(new String[list.size()]); @@ -1123,7 +1079,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase @Test public void testGroupOneLocalAllReg() throws Throwable { final String exprString = "firstvar; $*"; - List list = get_X86_REGS(); + List list = getRegistersFromGdb(); Collections.sort(list); list.addAll(0, Arrays.asList(new String[] { "firstvar" })); final String[] children = list.toArray(new String[list.size()]); @@ -1205,7 +1161,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase @Test public void testSortedAllReg() throws Throwable { final String exprString = "$*"; - List regList = get_X86_REGS(); + List regList = getRegistersFromGdb(); Collections.sort(regList); final String[] children = regList.toArray(new String[0]); @@ -1250,7 +1206,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase @Test public void testSeparatlySorted() throws Throwable { final String exprString = "$*; *"; - List list = get_X86_REGS(); + List list = getRegistersFromGdb(); Collections.sort(list); List localsList = Arrays.asList(fAllVariables); Collections.sort(localsList); diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIRegistersTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIRegistersTest.java index ff033bc75f6..0d4ef5b28d2 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIRegistersTest.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIRegistersTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.fail; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -57,65 +56,22 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.gdb.service.GDBRegisters; -import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.MIRegisters.MIRegisterDMC; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; -import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterNamesInfo; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase; import org.eclipse.cdt.tests.dsf.gdb.framework.ServiceEventWaitor; import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil; import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class MIRegistersTest extends BaseParametrizedTestCase { - // Static list of register names as obtained directly from GDB. - // We make it static it does not get re-set for every test - protected static List fRegisterNames = null; - - @BeforeClass - public static void initializeGlobals() { - // In case we run multiple GDB versions of this test - // in the same suite, we need to re-initialize the registers - // as they may change between GDB versions. - fRegisterNames = null; - } - - protected List get_X86_REGS() throws Throwable { - if (fRegisterNames == null) { - // The tests must run on different machines, so the set of registers can change. - // To deal with this we ask GDB for the list of registers. - // Note that we send an MI Command in this code and do not use the IRegister service; - // this is because we want to test the service later, comparing it to what we find - // by asking GDB directly. - Query query = new Query() { - @Override - protected void execute(DataRequestMonitor rm) { - IMICommandControl controlService = fServicesTracker.getService(IMICommandControl.class); - IContainerDMContext containerDmc = DMContexts.getAncestorOfType(fCompositeDmc, IContainerDMContext.class); - controlService.queueCommand(controlService.getCommandFactory().createMIDataListRegisterNames(containerDmc), rm); - } - }; - fSession.getExecutor().execute(query); - - MIDataListRegisterNamesInfo data = query.get(); - String[] names = data.getRegisterNames(); - - // Remove registers with empty names since the service also - // remove them. I don't know why GDB returns such empty names. - fRegisterNames = new LinkedList(); - for (String name : names) { - if (!name.isEmpty()) { - fRegisterNames.add(name); - } - } - } - return fRegisterNames; + protected List getRegistersFromGdb() throws Throwable { + return SyncUtil.getRegistersFromGdb(getGdbVersion(), fCompositeDmc); } /* @@ -214,7 +170,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase { IRegisterDMContext[] regContexts = queryRegisters.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); - assertEquals("Wrong number of registers", get_X86_REGS().size(), regContexts.length); + assertEquals("Wrong number of registers", getRegistersFromGdb().size(), regContexts.length); return regContexts; } @@ -242,7 +198,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase { */ private IRegisterDMContext[] getTargetRegisters(final IFrameDMContext frameDmc) throws Throwable { IRegisterDMContext[] regContexts = getRegisters(new CompositeDMContext(new IDMContext[] { fCompositeDmc, frameDmc})); - assertEquals("Wrong number of registers", get_X86_REGS().size(), regContexts.length); + assertEquals("Wrong number of registers", getRegistersFromGdb().size(), regContexts.length); return regContexts; } @@ -265,7 +221,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase { MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); - assertEquals("Wrong number of registers", get_X86_REGS().size(), regDMCs.length); + assertEquals("Wrong number of registers", getRegistersFromGdb().size(), regDMCs.length); } @Test @@ -273,7 +229,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase { MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); - List regNames = get_X86_REGS(); + List regNames = getRegistersFromGdb(); IRegisterDMData[] datas = getRegistersData(regDMCs); @@ -547,7 +503,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase { } private String resolveStackPointerName() throws Throwable { - List regNames = get_X86_REGS(); + List regNames = getRegistersFromGdb(); // for 64 bits String sp_name = "rsp";