1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +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;
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<String, List<String>> 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<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.
*

View file

@ -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<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.
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);
/**
* Return a new, mutable list with '$' prefixed on each register
*/
protected List<String> getRegistersFromGdb() throws Throwable {
List<String> 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<String> regList = get_X86_REGS();
List<String> 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<String> list = get_X86_REGS();
List<String> 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<String> list = get_X86_REGS();
List<String> 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<String> list = get_X86_REGS();
List<String> 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<String> regList = get_X86_REGS();
List<String> 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<String> list = get_X86_REGS();
List<String> list = getRegistersFromGdb();
Collections.sort(list);
List<String> localsList = Arrays.asList(fAllVariables);
Collections.sort(localsList);

View file

@ -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<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;
protected List<String> 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<String> regNames = get_X86_REGS();
List<String> regNames = getRegistersFromGdb();
IRegisterDMData[] datas = getRegistersData(regDMCs);
@ -547,7 +503,7 @@ public class MIRegistersTest extends BaseParametrizedTestCase {
}
private String resolveStackPointerName() throws Throwable {
List<String> regNames = get_X86_REGS();
List<String> regNames = getRegistersFromGdb();
// for 64 bits
String sp_name = "rsp";