1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-05 00:36:16 +02:00

Bug 532297: Cache registers per version of GDB

Change-Id: I2da702830f01035b99dc61fcdfb9e7a43fcc8d55
This commit is contained in:
Jonah Graham 2018-03-11 19:28:58 +00:00
parent b4ac2d3ebf
commit 9537e51cf3
3 changed files with 74 additions and 108 deletions

View file

@ -16,13 +16,16 @@
package org.eclipse.cdt.tests.dsf.gdb.framework; package org.eclipse.cdt.tests.dsf.gdb.framework;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Callable; 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.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo; 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.MIBreakpoint;
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataListRegisterNamesInfo;
import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil.DefaultTimeouts.ETimeout; import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil.DefaultTimeouts.ETimeout;
@ -100,11 +104,18 @@ public class SyncUtil {
private static ISourceLookup fSourceLookup; 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<String, List<String>> fRegisterNames = new HashMap<>();
// Initialize some common things, once the session has been established // Initialize some common things, once the session has been established
public static void initialize(DsfSession session) throws Exception { public static void initialize(DsfSession session) throws Exception {
fSession = session; fSession = session;
Runnable runnable = new Runnable() { Runnable runnable = new Runnable() {
@Override @Override
public void run() { public void run() {
DsfServicesTracker tracker = new DsfServicesTracker( DsfServicesTracker tracker = new DsfServicesTracker(
@ -857,6 +868,49 @@ public class SyncUtil {
return result; return result;
} }
/**
* Get the registers directly from GDB (without using the registers service)
* @param gdbVersion
* @param context
* @return
* @throws Throwable
*/
public static List<String> 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<MIDataListRegisterNamesInfo> query = new Query<MIDataListRegisterNamesInfo>() {
@Override
protected void execute(DataRequestMonitor<MIDataListRegisterNamesInfo> 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<String> registerNames = new LinkedList<String>();
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. * Read data from memory.
* *

View file

@ -20,6 +20,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; 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.IFormattedValues.FormattedValueDMData;
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext; import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
import org.eclipse.cdt.dsf.debug.service.IRegisters2; 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.IRunControl.StepType;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; 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.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.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIExpressions; import org.eclipse.cdt.dsf.mi.service.IMIExpressions;
import org.eclipse.cdt.dsf.mi.service.MIRegisters.MIRegisterDMC; 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.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.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase; 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.framework.SyncUtil;
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin; import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
@ -106,53 +103,12 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase
//************************************************************************************** //**************************************************************************************
// Utility methods // Utility methods
//************************************************************************************** //**************************************************************************************
/**
// Static list of register names as obtained directly from GDB. * Return a new, mutable list with '$' prefixed on each register
// We make it static so it does not get re-set for every test */
protected static List<String> fRegisterNames = null; protected List<String> getRegistersFromGdb() throws Throwable {
List<String> registersFromGdb = SyncUtil.getRegistersFromGdb(getGdbVersion(), SyncUtil.getContainerContext());
@BeforeClass return registersFromGdb.stream().map(n -> "$" + n).collect(Collectors.toCollection(LinkedList::new));
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<String> 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<MIDataListRegisterNamesInfo> query = new Query<MIDataListRegisterNamesInfo>() {
@Override
protected void execute(DataRequestMonitor<MIDataListRegisterNamesInfo> 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<String>();
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<String>(fRegisterNames);
} }
final static String[] fAllVariables = new String[] { "firstarg", "firstvar", "ptrvar", "secondarg", "secondvar", "var", "var2" }; 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 { public void testMatchAllRegs() throws Throwable {
final String exprString = "$*"; final String exprString = "$*";
final String exprString2 = "=$*"; final String exprString2 = "=$*";
List<String> regList = get_X86_REGS(); List<String> regList = getRegistersFromGdb();
Collections.sort(regList); Collections.sort(regList);
final String[] children = regList.toArray(new String[0]); final String[] children = regList.toArray(new String[0]);
@ -1060,7 +1016,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase
@Test @Test
public void testGroupAllRegsAllLocals() throws Throwable { public void testGroupAllRegsAllLocals() throws Throwable {
final String exprString = "$*; *"; final String exprString = "$*; *";
List<String> list = get_X86_REGS(); List<String> list = getRegistersFromGdb();
Collections.sort(list); Collections.sort(list);
list.addAll(Arrays.asList(fAllVariables)); list.addAll(Arrays.asList(fAllVariables));
final String[] children = list.toArray(new String[list.size()]); final String[] children = list.toArray(new String[list.size()]);
@ -1083,7 +1039,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase
@Test @Test
public void testGroupAllLocalsAllRegs() throws Throwable { public void testGroupAllLocalsAllRegs() throws Throwable {
final String exprString = "*; $*"; final String exprString = "*; $*";
List<String> list = get_X86_REGS(); List<String> list = getRegistersFromGdb();
Collections.sort(list); Collections.sort(list);
list.addAll(0, Arrays.asList(fAllVariables)); list.addAll(0, Arrays.asList(fAllVariables));
final String[] children = list.toArray(new String[list.size()]); final String[] children = list.toArray(new String[list.size()]);
@ -1123,7 +1079,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase
@Test @Test
public void testGroupOneLocalAllReg() throws Throwable { public void testGroupOneLocalAllReg() throws Throwable {
final String exprString = "firstvar; $*"; final String exprString = "firstvar; $*";
List<String> list = get_X86_REGS(); List<String> list = getRegistersFromGdb();
Collections.sort(list); Collections.sort(list);
list.addAll(0, Arrays.asList(new String[] { "firstvar" })); list.addAll(0, Arrays.asList(new String[] { "firstvar" }));
final String[] children = list.toArray(new String[list.size()]); final String[] children = list.toArray(new String[list.size()]);
@ -1205,7 +1161,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase
@Test @Test
public void testSortedAllReg() throws Throwable { public void testSortedAllReg() throws Throwable {
final String exprString = "$*"; final String exprString = "$*";
List<String> regList = get_X86_REGS(); List<String> regList = getRegistersFromGdb();
Collections.sort(regList); Collections.sort(regList);
final String[] children = regList.toArray(new String[0]); final String[] children = regList.toArray(new String[0]);
@ -1250,7 +1206,7 @@ public class GDBPatternMatchingExpressionsTest extends BaseParametrizedTestCase
@Test @Test
public void testSeparatlySorted() throws Throwable { public void testSeparatlySorted() throws Throwable {
final String exprString = "$*; *"; final String exprString = "$*; *";
List<String> list = get_X86_REGS(); List<String> list = getRegistersFromGdb();
Collections.sort(list); Collections.sort(list);
List<String> localsList = Arrays.asList(fAllVariables); List<String> localsList = Arrays.asList(fAllVariables);
Collections.sort(localsList); Collections.sort(localsList);

View file

@ -24,7 +24,6 @@ import static org.junit.Assert.fail;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; 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.IRunControl.StepType;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.gdb.service.GDBRegisters; 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.MIRegisters.MIRegisterDMC;
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; 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.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase; 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.ServiceEventWaitor;
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil; import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil;
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin; import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
@RunWith(Parameterized.class) @RunWith(Parameterized.class)
public class MIRegistersTest extends BaseParametrizedTestCase { public class MIRegistersTest extends BaseParametrizedTestCase {
// Static list of register names as obtained directly from GDB. protected List<String> getRegistersFromGdb() throws Throwable {
// We make it static it does not get re-set for every test return SyncUtil.getRegistersFromGdb(getGdbVersion(), fCompositeDmc);
protected static List<String> 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<String> 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<MIDataListRegisterNamesInfo> query = new Query<MIDataListRegisterNamesInfo>() {
@Override
protected void execute(DataRequestMonitor<MIDataListRegisterNamesInfo> 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<String>();
for (String name : names) {
if (!name.isEmpty()) {
fRegisterNames.add(name);
}
}
}
return fRegisterNames;
} }
/* /*
@ -214,7 +170,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase {
IRegisterDMContext[] regContexts = queryRegisters.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); 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; return regContexts;
} }
@ -242,7 +198,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase {
*/ */
private IRegisterDMContext[] getTargetRegisters(final IFrameDMContext frameDmc) throws Throwable { private IRegisterDMContext[] getTargetRegisters(final IFrameDMContext frameDmc) throws Throwable {
IRegisterDMContext[] regContexts = getRegisters(new CompositeDMContext(new IDMContext[] { fCompositeDmc, frameDmc})); 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; return regContexts;
} }
@ -265,7 +221,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase {
MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); 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 @Test
@ -273,7 +229,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase {
MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc);
List<String> regNames = get_X86_REGS(); List<String> regNames = getRegistersFromGdb();
IRegisterDMData[] datas = getRegistersData(regDMCs); IRegisterDMData[] datas = getRegistersData(regDMCs);
@ -547,7 +503,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase {
} }
private String resolveStackPointerName() throws Throwable { private String resolveStackPointerName() throws Throwable {
List<String> regNames = get_X86_REGS(); List<String> regNames = getRegistersFromGdb();
// for 64 bits // for 64 bits
String sp_name = "rsp"; String sp_name = "rsp";