| /******************************************************************************* |
| * Copyright (c) 2009, 2015 Ericsson 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: |
| * Ericsson - initial API and implementation |
| * Alvaro Sanchez-Leon (Ericsson) - Make Registers View specific to a frame (Bug 323552) |
| * Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747) |
| * Simon Marchi (Ericsson) - Adapt test code to thread platform compatibility layer. |
| *******************************************************************************/ |
| package org.eclipse.cdt.tests.dsf.gdb.tests; |
| |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.hamcrest.core.IsEqual.equalTo; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| 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; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; |
| import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; |
| import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; |
| import org.eclipse.cdt.dsf.concurrent.DsfExecutor; |
| import org.eclipse.cdt.dsf.concurrent.ImmediateCountingRequestMonitor; |
| import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; |
| import org.eclipse.cdt.dsf.concurrent.Query; |
| import org.eclipse.cdt.dsf.datamodel.CompositeDMContext; |
| import org.eclipse.cdt.dsf.datamodel.DMContexts; |
| import org.eclipse.cdt.dsf.datamodel.IDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegistersChangedDMEvent; |
| import org.eclipse.cdt.dsf.debug.service.IRegisters2; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl; |
| import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; |
| 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; |
| } |
| |
| /* |
| * Name of the executable |
| */ |
| private static final String EXEC_NAME = "MultiThread.exe"; |
| private static final String SOURCE_NAME = "MultiThread.cc"; |
| |
| private static final String GROUP_X = "GroupX"; |
| private static final String GROUP_Y = "GroupY"; |
| private static final String PROPOSE_GROUP_NAME_BASE = "Group_"; |
| |
| private DsfSession fSession; |
| private DsfServicesTracker fServicesTracker; |
| private IDMContext fCompositeDmc; |
| private IRegisters2 fRegService; |
| private IRunControl fRunControl; |
| private Integer fGroupNameSuffix; |
| |
| @Override |
| public void doBeforeTest() throws Exception { |
| super.doBeforeTest(); |
| |
| fSession = getGDBLaunch().getSession(); |
| resolveLineTagLocations(SOURCE_NAME, MIRunControlTest.LINE_TAGS); |
| |
| Runnable runnable = new Runnable() { |
| @Override |
| public void run() { |
| // We obtain the services we need after the new |
| // launch has been performed |
| fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId()); |
| |
| fRegService = (IRegisters2) fServicesTracker.getService(IRegisters.class); |
| fRunControl = fServicesTracker.getService(IRunControl.class); |
| } |
| }; |
| |
| fSession.getExecutor().submit(runnable).get(); |
| |
| //resolve the execution context |
| IFrameDMContext frameDmc = SyncUtil.getStackFrame(getInitialStoppedEvent().getDMContext(), 0); |
| |
| //resolve the container context |
| IContainerDMContext containerDmc = DMContexts.getAncestorOfType(getInitialStoppedEvent().getDMContext(), IContainerDMContext.class); |
| //The container dmc is expected to contain the frame and container context |
| fCompositeDmc = new CompositeDMContext(new IDMContext[] { containerDmc, frameDmc }); |
| fGroupNameSuffix = 0; |
| } |
| |
| @Override |
| protected void setLaunchAttributes() { |
| super.setLaunchAttributes(); |
| |
| setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EXEC_PATH + EXEC_NAME); |
| |
| } |
| |
| |
| @Override |
| public void doAfterTest() throws Exception { |
| super.doAfterTest(); |
| |
| if (fServicesTracker!=null) fServicesTracker.dispose(); |
| fRegService = null; |
| } |
| |
| /* |
| * This is a common support method which gets the Register Group Information from target |
| */ |
| private IRegisterGroupDMContext getTargetRegisterGroup() throws Throwable { |
| //Get all the registers from the Container (Process) |
| IRegisterDMContext[] registers = getRegisters(fCompositeDmc); |
| assertTrue(registers.length > 0); |
| |
| //Get the register group from any of the register contexts |
| IRegisterGroupDMContext regGroupsDMC = DMContexts.getAncestorOfType(registers[0], IRegisterGroupDMContext.class); |
| assertNotNull(regGroupsDMC); |
| |
| return regGroupsDMC; |
| } |
| |
| /* |
| * This is a common support method which gets the Registers names. |
| */ |
| private IRegisterDMContext[] getAllRegisters(final IFrameDMContext frameDmc) throws Throwable { |
| |
| Query<IRegisterDMContext[]> queryRegisters = new Query<IRegisterDMContext[]>() { |
| @Override |
| protected void execute(DataRequestMonitor<IRegisterDMContext[]> rm) { |
| fRegService.getRegisters(new CompositeDMContext(new IDMContext[] { fCompositeDmc, frameDmc }), rm); |
| } |
| }; |
| |
| fSession.getExecutor().execute(queryRegisters); |
| |
| IRegisterDMContext[] regContexts = queryRegisters.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| |
| assertEquals("Wrong number of registers", get_X86_REGS().size(), regContexts.length); |
| |
| return regContexts; |
| } |
| |
| /* |
| * Get the Registers for the specified composite context |
| */ |
| private IRegisterDMContext[] getRegisters(final IDMContext dmc) throws Throwable { |
| |
| Query<IRegisterDMContext[]> queryRegistersDmc = new Query<IRegisterDMContext[]>() { |
| @Override |
| protected void execute(DataRequestMonitor<IRegisterDMContext[]> rm) { |
| fRegService.getRegisters(dmc, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryRegistersDmc); |
| IRegisterDMContext[] regContexts = queryRegistersDmc.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| |
| return(regContexts); |
| } |
| |
| /* |
| * This is a common support method which gets the Register context of root group over the specified frame context |
| */ |
| 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); |
| |
| return regContexts; |
| } |
| |
| /************************************************************************* |
| * |
| * The tests for the register service. |
| * |
| *************************************************************************/ |
| @Test |
| public void resolveTargetRegisterGroup() throws Throwable { |
| final IRegisterGroupDMContext regGroupsDMC = getTargetRegisterGroup(); |
| IRegisterGroupDMData data = getRegisterGroupData(regGroupsDMC); |
| |
| assertEquals("Main register group's name", "General Registers", data.getName()); |
| } |
| |
| @Test |
| public void resolveTargetRegistersLength() throws Throwable { |
| 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); |
| } |
| |
| @Test |
| public void getRegisters() throws Throwable { |
| MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); |
| IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); |
| final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); |
| List<String> regNames = get_X86_REGS(); |
| |
| IRegisterDMData[] datas = getRegistersData(regDMCs); |
| |
| for(IRegisterDMData data: datas){ |
| String regName = data.getName(); |
| assertTrue("GDB does not support register name: " + regName, regNames.contains(regName)); |
| } |
| } |
| |
| private IRegisterDMData[] getRegistersData(final IRegisterDMContext[] regDMCs) throws InterruptedException, ExecutionException { |
| |
| Query<IRegisterDMData[]> query = new Query<IRegisterDMData[]>() { |
| @Override |
| protected void execute(DataRequestMonitor<IRegisterDMData[]> rm) { |
| final IRegisterDMData[] datas = new IRegisterDMData[regDMCs.length]; |
| rm.setData(datas); |
| final CountingRequestMonitor countingRm = new ImmediateCountingRequestMonitor(rm); |
| countingRm.setDoneCount(regDMCs.length); |
| for (int i = 0; i < regDMCs.length; i++) { |
| final int index = i; |
| fRegService.getRegisterData(regDMCs[index], new ImmediateDataRequestMonitor<IRegisterDMData>(countingRm) { |
| @Override |
| protected void handleSuccess() { |
| datas[index] = getData(); |
| countingRm.done(); |
| } |
| }); |
| } |
| |
| } |
| }; |
| |
| fSession.getExecutor().execute(query); |
| |
| return query.get(); |
| } |
| |
| private String getModelDataForRegisterDataValue(IFrameDMContext frameDmc, String format, int regNo) throws Throwable { |
| final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); |
| return getModelDataForRegisterDataValue(regDMCs[regNo], format); |
| } |
| |
| private String getModelDataForRegisterDataValue(IRegisterDMContext registerDmc, String format) throws Throwable { |
| |
| final FormattedValueDMContext valueDmc = fRegService.getFormattedValueContext(registerDmc, format); |
| |
| Query<FormattedValueDMData> queryFormattedData = new Query<FormattedValueDMData>() { |
| @Override |
| protected void execute(DataRequestMonitor<FormattedValueDMData> rm) { |
| fRegService.getFormattedExpressionValue(valueDmc, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryFormattedData); |
| |
| FormattedValueDMData data = queryFormattedData.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| return data.getFormattedValue(); |
| } |
| |
| |
| @Test |
| public void getModelDataForRegisterDataValueInDifferentNumberFormats() throws Throwable { |
| MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); |
| IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); |
| |
| // Make sure register #0 contains a known value. |
| writeRegister(frameDmc, 0, "0x1234", IFormattedValues.HEX_FORMAT); |
| |
| String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0); |
| assertThat(Long.parseLong(val), equalTo(0x1234L)); |
| |
| val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, 0); |
| assertTrue("Register Value is not in HEX_FORMAT: " + val, val.startsWith("0x")); |
| assertThat(Long.parseLong(val.substring(2), 16), equalTo(0x1234L)); |
| |
| val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, 0); |
| assertThat(Long.parseLong(val, 2), equalTo(0x1234L)); |
| |
| val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.DECIMAL_FORMAT, 0); |
| assertThat(Long.parseLong(val), equalTo(0x1234L)); |
| |
| val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, 0); |
| assertTrue("Register Value is not in OCTAL_FORMAT: " + val, val.startsWith("0")); |
| assertThat(Long.parseLong(val.substring(1), 8), equalTo(0x1234L)); |
| } |
| |
| @Test |
| public void compareRegisterForMultipleExecutionContexts() throws Throwable { |
| MIStoppedEvent stoppedEvent = SyncUtil.runToLocation(SOURCE_NAME + ':' |
| + getLineForTag("LINE_MAIN_ALL_THREADS_STARTED")); |
| |
| // Get the thread IDs |
| final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(stoppedEvent.getDMContext(), IContainerDMContext.class); |
| |
| Query<IExecutionDMContext[]> queryExecutionContexts = new Query<IExecutionDMContext[]>() { |
| @Override |
| protected void execute(DataRequestMonitor<IExecutionDMContext[]> rm) { |
| fRunControl.getExecutionContexts(containerDmc, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryExecutionContexts); |
| |
| IExecutionDMContext[] ctxts = queryExecutionContexts.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| |
| assertNotNull(ctxts); |
| assertTrue(ctxts.length > 1); |
| |
| // Get stack frame for thread 2 |
| IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(ctxts[1], 0); |
| |
| String thread2RegVal0 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 0); |
| String thread2RegVal1 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 1); |
| String thread2RegVal2 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 2); |
| String thread2RegVal3 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 3); |
| String thread2RegVal4 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 4); |
| String thread2RegVal5 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 5); |
| |
| // Get stack frame for thread 1 |
| IFrameDMContext frameDmc1 = SyncUtil.getStackFrame(ctxts[0], 0); |
| |
| getModelDataForRegisterDataValue(frameDmc1, IFormattedValues.NATURAL_FORMAT, 0); |
| |
| // Re-set the execution context to 2 and Fetch from the Cache |
| String dupliThread2RegVal0 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 0); |
| String dupliThread2RegVal1 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 1); |
| String dupliThread2RegVal2 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 2); |
| String dupliThread2RegVal3 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 3); |
| String dupliThread2RegVal4 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 4); |
| String dupliThread2RegVal5 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 5); |
| |
| // If Values not equal , then context haven't been re-set properly |
| assertEquals("Multiple context not working. Execution Context is not reset to 2", thread2RegVal0, dupliThread2RegVal0); |
| assertEquals("Multiple context not working. Execution Context is not reset to 2", thread2RegVal1, dupliThread2RegVal1); |
| assertEquals("Multiple context not working. Execution Context is not reset to 2", thread2RegVal2, dupliThread2RegVal2); |
| assertEquals("Multiple context not working. Execution Context is not reset to 2", thread2RegVal3, dupliThread2RegVal3); |
| assertEquals("Multiple context not working. Execution Context is not reset to 2", thread2RegVal4, dupliThread2RegVal4); |
| assertEquals("Multiple context not working. Execution Context is not reset to 2", thread2RegVal5, dupliThread2RegVal5); |
| |
| } |
| |
| private void writeRegister(IFrameDMContext frameDmc, final int regIndex, final String regValue, final String formatId) throws Throwable { |
| final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); |
| writeRegister(regDMCs[regIndex], regValue, formatId); |
| } |
| |
| private void writeRegister(final IRegisterDMContext registerDmc, final String regValue, final String formatId) throws Throwable { |
| |
| Query<Object> queryAction = new Query<Object>() { |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| fRegService.writeRegister(registerDmc, regValue, formatId, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryAction); |
| queryAction.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| /** |
| * Waits for IRegistersChangedDMEvent(s) during a time interval, collects them and returns them after timeout |
| */ |
| private List<IRegistersChangedDMEvent> writeRegisterWaitNotication(final IRegisterDMContext registerDmc, final String regValue, final String formatId) |
| throws Throwable { |
| ServiceEventWaitor<IRegistersChangedDMEvent> eventWaitor = |
| new ServiceEventWaitor<IRegistersChangedDMEvent>(fSession, IRegistersChangedDMEvent.class); |
| |
| writeRegister(registerDmc, regValue, formatId); |
| |
| return eventWaitor.waitForEvents(TestsPlugin.massageTimeout(3000)); |
| } |
| |
| |
| @Test |
| public void writeRegisterNaturalFormat() throws Throwable { |
| MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); |
| IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); |
| String regValue = "10"; |
| int regIndex = 3; |
| writeRegister(frameDmc, 3, regValue, IFormattedValues.NATURAL_FORMAT); |
| String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, regIndex); |
| assertEquals("Failed writing register", regValue, val); |
| } |
| |
| @Test |
| public void writeRegisterHEXFormat() throws Throwable { |
| MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); |
| IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); |
| String regValue = "0x10"; |
| int regIndex = 3; |
| writeRegister(frameDmc, 3, regValue, IFormattedValues.HEX_FORMAT); |
| String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, regIndex); |
| assertEquals("Failed writing register", regValue, val); |
| } |
| |
| @Test |
| public void writeRegisterBinaryFormat() throws Throwable { |
| MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); |
| IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); |
| String regValue = "100101001"; |
| int regIndex = 3; |
| writeRegister(frameDmc, 3, regValue, IFormattedValues.BINARY_FORMAT); |
| String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, regIndex); |
| assertEquals("Failed writing register", regValue, val); |
| } |
| |
| @Test |
| public void writeRegisterOctalFormat() throws Throwable { |
| MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); |
| IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); |
| // String regValue = "10"; |
| String regValue = "012"; |
| int regIndex = 3; |
| writeRegister(frameDmc, 3, regValue, IFormattedValues.OCTAL_FORMAT); |
| String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, regIndex); |
| assertEquals("Failed writing register", regValue, val); |
| } |
| |
| /** |
| * This test validates retrieval of different values for the same register used on different frames |
| */ |
| @Test |
| public void frameSpecificValues() throws Throwable { |
| // Step to a multi-level stack to be able to test different stack frames |
| SyncUtil.runToLocation("PrintHello"); |
| MIStoppedEvent stoppedEvent = SyncUtil.step(StepType.STEP_OVER); |
| int depth = SyncUtil.getStackDepth(stoppedEvent.getDMContext()); |
| |
| // we need at least 2 levels of stack frame to continue this test. |
| // note: the depth is glibc-version-dependent |
| assertTrue(depth >= 2); |
| |
| // Resolve the register name of the stack pointer |
| String sp_name = resolveStackPointerName(); |
| assertNotNull(sp_name); |
| |
| // Get the stack pointer value for frame0 |
| IFrameDMContext frame0 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); |
| IRegisterDMContext[] registers_f0 = getTargetRegisters(frame0); |
| MIRegisterDMC sp_reg_f0 = (MIRegisterDMC) findStackPointerRegister(sp_name, registers_f0); |
| assertNotNull(sp_reg_f0); |
| String sp_f0_str = getModelDataForRegisterDataValue(frame0, IFormattedValues.HEX_FORMAT, sp_reg_f0.getRegNo()); |
| |
| // Get the stack pointer value for frame1 |
| IFrameDMContext frame1 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1); |
| IRegisterDMContext[] registers_f1 = getTargetRegisters(frame1); |
| MIRegisterDMC sp_reg_f1 = (MIRegisterDMC) findStackPointerRegister(sp_name, registers_f1); |
| assertNotNull(sp_reg_f1); |
| String sp_f1_str = getModelDataForRegisterDataValue(frame1, IFormattedValues.HEX_FORMAT, sp_reg_f1.getRegNo()); |
| |
| //The stack pointer's are not expected to be the same among frames |
| assertFalse("Stack pointers shall be different among frames", sp_f0_str.equals(sp_f1_str)); |
| } |
| |
| private IRegisterDMContext findStackPointerRegister(String sp_name, IRegisterDMContext[] registerDMCs) throws InterruptedException, ExecutionException { |
| IRegisterDMData[] registersData = getRegistersData(registerDMCs); |
| for (int i = 0; i < registersData.length; i++) { |
| IRegisterDMData registerData = registersData[i]; |
| |
| if (registerData.getName().equals(sp_name)) { |
| return registerDMCs[i]; |
| } |
| } |
| |
| return null; |
| } |
| |
| private String resolveStackPointerName() throws Throwable { |
| List<String> regNames = get_X86_REGS(); |
| |
| // for 64 bits |
| String sp_name = "rsp"; |
| if (regNames.contains(sp_name)) { |
| return sp_name; |
| } |
| |
| // for 32 bits |
| sp_name = "esp"; |
| if (regNames.contains(sp_name)) { |
| return sp_name; |
| } |
| |
| // for 16 bits |
| sp_name = "sp"; |
| if (regNames.contains(sp_name)) { |
| return sp_name; |
| } |
| |
| return null; |
| } |
| |
| @Test |
| public void getRegisterGroupsData() throws Throwable { |
| int grpsIncrement = 3; |
| |
| //Group name to Group description |
| Map<String, String> groupNameToDescMap = new HashMap<>(); |
| groupNameToDescMap.put("Group_1", ""); |
| groupNameToDescMap.put("Group_2", ""); |
| groupNameToDescMap.put("Group_3", ""); |
| groupNameToDescMap.put("General Registers", "General Purpose and FPU Register Group"); |
| |
| //Tracking groups found |
| Set<String> groupsFound = new HashSet<>(); |
| |
| addRegisterGroups(grpsIncrement); |
| final IRegisterDMContext[] regInGroup = getRegisters(0, 4); |
| |
| IRegisterGroupDMData[] groupsData = getRegisterGroupsData(regInGroup[0]); |
| //increment + root |
| assertEquals(grpsIncrement + 1, groupsData.length); |
| for (IRegisterGroupDMData grpData: groupsData) { |
| // Validate group name |
| assertTrue(groupNameToDescMap.containsKey(grpData.getName())); |
| String grpDataDesc = grpData.getDescription(); |
| String expectedName = groupNameToDescMap.get(grpData.getName()); |
| |
| //Validate group description |
| assertEquals(expectedName, grpDataDesc); |
| groupsFound.add(grpData.getName()); |
| } |
| |
| //Make sure all expected groups were found |
| assertEquals(groupNameToDescMap.size(), groupsFound.size()); |
| } |
| |
| @Test |
| public void canAddRegisterGroup() throws Throwable { |
| // only root group expected |
| final IRegisterGroupDMContext[] groups = getRegisterGroups(1); |
| assertEquals("Unexpected groups present, only root was expected", 1, groups.length); |
| assertTrue("Can not Add register groups", canAddRegisterGroup(groups[0])); |
| } |
| |
| @Test |
| public void canNotEditRootRegisterGroup() throws Throwable { |
| // only root group expected |
| final IRegisterGroupDMContext[] groups = getRegisterGroups(1); |
| assertEquals("Unexpected groups present, only root was expected", 1, groups.length); |
| |
| assertFalse("Not expected to allow the editing of the root register group", canEditRegisterGroup(groups[0])); |
| } |
| |
| @Test |
| public void canNotEditUnknownRegisterGroup() throws Throwable { |
| // only root group expected |
| final IRegisterGroupDMContext group = new IRegisterGroupDMContext() { |
| |
| @Override |
| public String getSessionId() { |
| return "session"; |
| } |
| |
| @Override |
| public IDMContext[] getParents() { |
| return new IDMContext[0]; |
| } |
| |
| @Override |
| public <T> T getAdapter(Class<T> adapter) { |
| return null; |
| } |
| }; |
| |
| assertFalse("Not expected to allow editing of a non registered group", canEditRegisterGroup(group)); |
| } |
| |
| @Test |
| public void canEditRegisterGroup() throws Throwable { |
| // only root group expected |
| final IRegisterGroupDMContext[] groups = getRegisterGroups(1); |
| assertEquals("Unexpected groups present, only root was expected", 1, groups.length); |
| |
| IRegisterGroupDMContext group = addDefaultUserGroup(); |
| assertTrue("Was not allowed to edit register group", canEditRegisterGroup(group)); |
| } |
| |
| /** |
| * @throws Throwable |
| */ |
| @Test |
| public void addRegisterGroups() throws Throwable { |
| // Define a subset of registers to create a register group (from, to) |
| final IRegisterDMContext[] regInGroup = getRegisters(0, 4); |
| |
| // Adding three groups with default names |
| String groupName = proposeGroupName(); |
| addGroup(groupName, regInGroup); |
| // Resolve the new group's sequence number from the pattern "Group_sequenceN" |
| int starting_sequence = resolveGroupNameSequence(groupName); |
| |
| groupName = proposeGroupName(); |
| addGroup(groupName, regInGroup); |
| |
| groupName = proposeGroupName(); |
| addGroup(groupName, regInGroup); |
| |
| // Retrieve the existing groups, expected and validated to root + 3 |
| IRegisterGroupDMContext[] groups = getRegisterGroups(4); |
| |
| // The groups are returned in reversed order to present latest created |
| // first i.e. index 0 |
| // The newest group shall be at the top then i.e. 0 |
| |
| //Add a valid execution context to resolve the register values |
| IFrameDMContext frameDmc = DMContexts.getAncestorOfType(regInGroup[0], IFrameDMContext.class); |
| CompositeDMContext compositeDmc = new CompositeDMContext(new IDMContext[]{frameDmc, groups[0]}); |
| IRegisterDMContext[] readRegisters = getRegisters(compositeDmc); |
| |
| // Same order, same data and same values are expected, although different instances to different parents |
| assertTrue(sameData(regInGroup, readRegisters, false)); |
| |
| // Assert the last created group name |
| IRegisterGroupDMData groupData = getRegisterGroupData(groups[0]); |
| // 2 additional groups after creation of the base group in this test case |
| assertEquals("Group_" + (starting_sequence + 2), groupData.getName()); |
| } |
| |
| @Test |
| public void editRegisterGroup() throws Throwable { |
| // Get Register Groups |
| IRegisterGroupDMContext[] groups = getRegisterGroups(1); |
| assertEquals("unexpected groups present", 1, groups.length); |
| |
| IRegisterGroupDMContext group = addDefaultUserGroup(); |
| |
| IRegisterDMContext[] origRegisters = getRegisters(group); |
| |
| // Assert the default group name |
| IRegisterGroupDMData groupData = getRegisterGroupData(group); |
| assertEquals(GROUP_X, groupData.getName()); |
| |
| // Registers to associate to exiting default group |
| IRegisterDMContext[] newRegisters = getRegisters(5, 9); |
| |
| // A different set of registers being assigned to the group |
| assertFalse((sameData(origRegisters, newRegisters, false))); |
| |
| // Modify the name and associated registers of the default group |
| editGroup(group, GROUP_Y, newRegisters); |
| |
| groupData = getRegisterGroupData(group); |
| assertEquals(GROUP_Y, groupData.getName()); |
| |
| IFrameDMContext frameDmc = DMContexts.getAncestorOfType(newRegisters[0], IFrameDMContext.class); |
| |
| //Read the context with a valid execution context |
| CompositeDMContext compositeDmc = new CompositeDMContext(new IDMContext[]{group, frameDmc}); |
| IRegisterDMContext[] readRegisters = getRegisters(compositeDmc); |
| |
| //Same data but not from the same parent group, newRegisters from root, readRegisters from GroupY |
| assertTrue(sameData(newRegisters, readRegisters, false)); |
| |
| } |
| |
| @Test |
| public void canRemoveRegisterGroup() throws Throwable { |
| // only root group expected |
| IRegisterGroupDMContext[] groups = getRegisterGroups(1); |
| assertFalse("Removal of root register group shall not be allowed", canRemoveRegisterGroups(groups)); |
| |
| //Add another two groups |
| // Define a subset of registers to create a register group (from, to) |
| final IRegisterDMContext[] regInGroup = getRegisters(0, 4); |
| |
| // Adding three groups with default names |
| String groupName = proposeGroupName(); |
| addGroup(groupName, regInGroup); |
| |
| groupName = proposeGroupName(); |
| addGroup(groupName, regInGroup); |
| |
| groupName = proposeGroupName(); |
| addGroup(groupName, regInGroup); |
| |
| // Retrieve the existing groups, expected and validated to root + 3 |
| groups = getRegisterGroups(4); |
| |
| //Remove the root group from the list, so the remaining can be validated |
| //as can be removed |
| groups = Arrays.copyOfRange(groups, 0, groups.length-1); |
| assertTrue("Not allowing removal of groups", canRemoveRegisterGroups(groups)); |
| |
| //remove the non root groups and validate the result |
| removeGroups(groups); |
| groups = getRegisterGroups(1); |
| } |
| |
| @Test |
| public void removeRegisterGroups() throws Throwable { |
| int grpsIncrement = 3; |
| addRegisterGroups(grpsIncrement); |
| |
| // Retrieve the existing groups, expected and validated to 1 root + 3 |
| IRegisterGroupDMContext[] groups = getRegisterGroups(1 + grpsIncrement); |
| |
| // remove one and assert the new size |
| IRegisterGroupDMContext[] remGroups = new IRegisterGroupDMContext[] { groups[0] }; |
| removeGroups(remGroups); |
| getRegisterGroups(grpsIncrement); // assert this to root + 2 |
| |
| // remove two more and assert the new size |
| remGroups = new IRegisterGroupDMContext[] { groups[1], groups[2] }; |
| removeGroups(remGroups); |
| getRegisterGroups(1); // assert this to only one i.e. root |
| |
| // attempt to remove root -- Shall not be allowed |
| remGroups = new IRegisterGroupDMContext[] { groups[3] }; |
| removeGroups(remGroups); |
| getRegisterGroups(1); // assert this to only one i.e. root |
| } |
| |
| /** |
| * The root group shall not be deleted i.e. ignore and preserved |
| */ |
| @Test |
| public void removeRegisterGroupsWithRoot() throws Throwable { |
| int grpsIncrement = 3; |
| addRegisterGroups(grpsIncrement); |
| |
| // Retrieve the existing groups, expected and validated to 1 root + 3 |
| IRegisterGroupDMContext[] groups = getRegisterGroups(1 + grpsIncrement); |
| |
| // Attempt to remove all i.e. root + user defined register groups |
| removeGroups(groups); |
| getRegisterGroups(1); // assert root is preserved |
| } |
| |
| |
| @Test |
| public void canRestoreRegisterGroups() throws Throwable { |
| int grpsIncrement = 3; |
| addRegisterGroups(grpsIncrement); |
| //Always able to restore to default |
| assertTrue(canRestoreDefaultGroups()); |
| } |
| |
| @Test |
| public void restoreRegisterGroups() throws Throwable { |
| int grpsIncrement = 3; |
| addRegisterGroups(grpsIncrement); |
| |
| restoreDefaultGroups(); |
| |
| // assert all groups are gone except root |
| getRegisterGroups(1); |
| } |
| |
| @Test |
| public void getRegisterNames() throws Throwable { |
| int grpsIncrement = 2; |
| addRegisterGroups(grpsIncrement); |
| IRegisterGroupDMContext[] groups = getRegisterGroups(3); // root + |
| // increment |
| |
| IRegisterDMContext[] regDmcs1 = getRegisters(groups[0]); |
| IRegisterDMContext[] regDmcs2 = getRegisters(groups[1]); |
| |
| IRegisterDMData[] regNames1 = getRegistersData(regDmcs1); |
| IRegisterDMData[] regNames2 = getRegistersData(regDmcs2); |
| |
| // assert the register names match on both groups |
| assertTrue(sameRegisterNames(regNames1, regNames2)); |
| } |
| |
| @Test |
| public void saveAndReadRegisterGroupData() throws Throwable { |
| //Only the default group is expected |
| int starting_sequence = 0; |
| |
| int grpsIncrement = 2; |
| addRegisterGroups(grpsIncrement); |
| getRegisterGroups(3); // root + 2 |
| |
| //The two steps below would ideally use a shutdown and the start of a new launch configuration within the same case. |
| //However the approach below accomplishes verification of saving and reading with out over complicating the current base test case structure. |
| |
| //trigger groups saving |
| saveRegGroups(); |
| |
| //trigger group reading from launch configuration |
| resetRegService(); |
| |
| IRegisterGroupDMContext[] groups = getRegisterGroups(3); // root + 2 |
| // Assert the last created group name |
| IRegisterGroupDMData groupData = getRegisterGroupData(groups[0]); |
| // 2 additional groups after creation of the base group in this test case |
| assertEquals("Group_" + (starting_sequence + grpsIncrement), groupData.getName()); |
| } |
| |
| /** |
| * All groups shall be able to write / update register values, These new value shall be propagated to any other |
| * group(s) containing this register |
| */ |
| @Test |
| public void writeRegisterFromUserGroup() throws Throwable { |
| // Define a subset of registers common to other register groups |
| // indexes (from, to) |
| final IRegisterDMContext[] regInRootGroup = getRegisters(0, 4); |
| String oirigVal = getModelDataForRegisterDataValue(regInRootGroup[0], IFormattedValues.NATURAL_FORMAT); |
| |
| // Get a handle to the execution contexts, same frame execution context for all actions |
| IFrameDMContext frameDmc = DMContexts.getAncestorOfType(regInRootGroup[0], IFrameDMContext.class); |
| |
| // create two user groups containing the same registers (new register instances based on root) |
| String groupNameOne = proposeGroupName(); |
| addGroup(groupNameOne, regInRootGroup); |
| |
| String groupNameTwo = proposeGroupName(); |
| addGroup(groupNameTwo, regInRootGroup); |
| |
| // Retrieve the existing groups, expected and validated to root + 2 |
| IRegisterGroupDMContext[] groups = getRegisterGroups(3); |
| |
| // Read registers from group one |
| // index 0 -> root group; index1 -> group one, index2 -> group Two |
| CompositeDMContext compositeDmc = new CompositeDMContext(new IDMContext[] { frameDmc, groups[1] }); |
| IRegisterDMContext[] groupOneRegisters = getRegisters(compositeDmc); |
| |
| // write a register value from register group one, register index 0 |
| Long iWrittenVal = Long.valueOf(oirigVal) + Long.valueOf(5); |
| String writtenValue = iWrittenVal.toString(); |
| List<IRegistersChangedDMEvent> eventNotifications = writeRegisterWaitNotication(groupOneRegisters[0], |
| writtenValue, IFormattedValues.NATURAL_FORMAT); |
| |
| // Validate IRegistersChangedDMEvent event notifications, one notification per group to trigger UI refresh |
| assertNotNull("No IRegistersChangedDMEvent were generated from the register value update", eventNotifications); |
| assertEquals("Incorrect number of IRegistersChangedDMEvent notifications, expecting one per group", 3, |
| eventNotifications.size()); |
| |
| // read the register value from user group two |
| compositeDmc = new CompositeDMContext(new IDMContext[] { frameDmc, groups[2] }); |
| IRegisterDMContext[] groupTwoRegisters = getRegisters(compositeDmc); |
| String readVal = getModelDataForRegisterDataValue(groupTwoRegisters[0], IFormattedValues.NATURAL_FORMAT); |
| |
| // assert the value from group two has been updated |
| assertEquals( |
| "Register[0] Value read from group two does not correspond to updated value written from group one", |
| writtenValue, readVal); |
| |
| // read the register value from the root register group |
| readVal = getModelDataForRegisterDataValue(regInRootGroup[0], IFormattedValues.NATURAL_FORMAT); |
| |
| // assert the value from root group has also been updated |
| assertEquals( |
| "Register[0] Value read from root group does not correspond to updated value written from group one", |
| writtenValue, readVal); |
| |
| } |
| |
| /** |
| * Get an array with all available register groups |
| */ |
| private IRegisterGroupDMContext[] getRegisterGroups() throws Throwable { |
| |
| Query<IRegisterGroupDMContext[]> queryGroupsCtx = new Query<IRegisterGroupDMContext[]>() { |
| @Override |
| protected void execute(DataRequestMonitor<IRegisterGroupDMContext[]> rm) { |
| fRegService.getRegisterGroups(fCompositeDmc, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().execute(queryGroupsCtx); |
| |
| IRegisterGroupDMContext[] regGroupsDMCs = queryGroupsCtx.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| |
| return (regGroupsDMCs); |
| } |
| |
| /** |
| * Request the existing groups and validate an expected count |
| */ |
| private IRegisterGroupDMContext[] getRegisterGroups(int expectedCount) throws Throwable { |
| IRegisterGroupDMContext[] regGroupsDMCs = getRegisterGroups(); |
| assertEquals("Number of groups present", //$NON-NLS-1$ |
| expectedCount, regGroupsDMCs.length); |
| |
| return regGroupsDMCs; |
| } |
| |
| private String proposeGroupName() throws Throwable { |
| return PROPOSE_GROUP_NAME_BASE + ++fGroupNameSuffix; |
| } |
| |
| private boolean canAddRegisterGroup(final IDMContext context) throws Throwable { |
| Query<Boolean> queryAction = new Query<Boolean>() { |
| @Override |
| protected void execute(DataRequestMonitor<Boolean> rm) { |
| fRegService.canAddRegisterGroup(context, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryAction); |
| return queryAction.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private boolean canEditRegisterGroup(final IRegisterGroupDMContext context) throws Throwable { |
| Query<Boolean> queryAction = new Query<Boolean>() { |
| @Override |
| protected void execute(DataRequestMonitor<Boolean> rm) { |
| fRegService.canEditRegisterGroup(context, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryAction); |
| return queryAction.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private boolean canRemoveRegisterGroups(final IRegisterGroupDMContext[] groupsContext) throws Throwable { |
| Query<Boolean> queryAction = new Query<Boolean>() { |
| @Override |
| protected void execute(DataRequestMonitor<Boolean> rm) { |
| fRegService.canRemoveRegisterGroups(groupsContext, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryAction); |
| return queryAction.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private void addGroup(final String groupName, final IRegisterDMContext[] regIndexes) throws Throwable { |
| |
| if (regIndexes == null || regIndexes.length < 1) { |
| fail("Invalid argument regIndexes"); |
| return; |
| } |
| |
| Query<Object> queryAction = new Query<Object>() { |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| IContainerDMContext contDmc = DMContexts.getAncestorOfType(regIndexes[0], IContainerDMContext.class); |
| fRegService.addRegisterGroup(contDmc, groupName, regIndexes, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryAction); |
| queryAction.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private void editGroup(final IRegisterGroupDMContext group, final String newGroupName, final IRegisterDMContext[] regIndexes) throws Throwable { |
| |
| Query<Object> queryAction = new Query<Object>() { |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| fRegService.editRegisterGroup(group, newGroupName, regIndexes, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryAction); |
| queryAction.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private void removeGroups(final IRegisterGroupDMContext[] groups) throws Throwable { |
| |
| Query<Object> queryAction = new Query<Object>() { |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| fRegService.removeRegisterGroups(groups, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(queryAction); |
| queryAction.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private boolean canRestoreDefaultGroups() throws Throwable { |
| Query<Boolean> queryCanRestore = new Query<Boolean>() { |
| |
| @Override |
| protected void execute(DataRequestMonitor<Boolean> rm) { |
| //selection context not used for the time being |
| fRegService.canRestoreDefaultGroups(null, rm); |
| } |
| |
| }; |
| |
| fRegService.getExecutor().submit(queryCanRestore); |
| |
| //Validate, we can always restore to defaults |
| return queryCanRestore.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private void restoreDefaultGroups() throws Throwable { |
| Query<Object> queryRestore = new Query<Object>() { |
| |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| //selection context not used for the time being |
| fRegService.restoreDefaultGroups(null, rm); |
| } |
| |
| }; |
| |
| fRegService.getExecutor().submit(queryRestore); |
| |
| queryRestore.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private void resetRegService() throws Throwable { |
| assert(fRegService instanceof GDBRegisters); |
| final GDBRegisters regManager = (GDBRegisters) fRegService; |
| Query<Object> queryReset = new Query<Object>() { |
| |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| regManager.reset(rm); |
| } |
| |
| }; |
| |
| regManager.getExecutor().submit(queryReset); |
| |
| queryReset.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private void saveRegGroups() throws Throwable { |
| assert(fRegService instanceof GDBRegisters); |
| final GDBRegisters regManager = (GDBRegisters) fRegService; |
| Query<Object> querySave = new Query<Object>() { |
| |
| @Override |
| protected void execute(DataRequestMonitor<Object> rm) { |
| regManager.save(); |
| rm.done(); |
| } |
| |
| }; |
| |
| regManager.getExecutor().submit(querySave); |
| |
| querySave.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| } |
| |
| private IRegisterDMData getRegisterData(final IRegisterDMContext registerDmc) throws Throwable { |
| Query<IRegisterDMData> registerDataQ = new Query<IRegisterDMData>() { |
| @Override |
| protected void execute(DataRequestMonitor<IRegisterDMData> rm) { |
| fRegService.getRegisterData(registerDmc, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(registerDataQ); |
| IRegisterDMData registerData = registerDataQ.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| assertNotNull(registerData); |
| |
| return registerData; |
| } |
| |
| private FormattedValueDMData getRegisterValue(final IRegisterDMContext registerDmc) throws Throwable { |
| Query<FormattedValueDMData> registerValueQ = new Query<FormattedValueDMData>() { |
| @Override |
| protected void execute(DataRequestMonitor<FormattedValueDMData> rm) { |
| FormattedValueDMContext valueDmc = new FormattedValueDMContext(fRegService, registerDmc, IFormattedValues.NATURAL_FORMAT); |
| fRegService.getFormattedExpressionValue(valueDmc, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(registerValueQ); |
| FormattedValueDMData registerValue = registerValueQ.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| assertNotNull(registerValue); |
| |
| return registerValue; |
| } |
| |
| private IRegisterGroupDMData getRegisterGroupData(final IRegisterGroupDMContext groupDmc) throws Throwable { |
| Query<IRegisterGroupDMData> groupDataQ = new Query<IRegisterGroupDMData>() { |
| @Override |
| protected void execute(DataRequestMonitor<IRegisterGroupDMData> rm) { |
| fRegService.getRegisterGroupData(groupDmc, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(groupDataQ); |
| IRegisterGroupDMData groupData = groupDataQ.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| assertNotNull(groupData); |
| |
| return groupData; |
| } |
| |
| private IRegisterGroupDMData[] getRegisterGroupsData(final IDMContext dmc) throws Throwable { |
| Query<IRegisterGroupDMData[]> groupDataQ = new Query<IRegisterGroupDMData[]>() { |
| @Override |
| protected void execute(DataRequestMonitor<IRegisterGroupDMData[]> rm) { |
| getRegisterGroupsData(dmc, rm); |
| } |
| }; |
| |
| fRegService.getExecutor().submit(groupDataQ); |
| IRegisterGroupDMData[] groupsData = groupDataQ.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS); |
| assertNotNull(groupsData); |
| |
| return groupsData; |
| } |
| |
| private void getRegisterGroupsData(final IDMContext dmc, final DataRequestMonitor<IRegisterGroupDMData[]> rm) { |
| assert (dmc != null); |
| final DsfExecutor executor = fRegService.getExecutor(); |
| // First get all register group contexts, any register context can be used to resolve the container context |
| fRegService.getRegisterGroups(dmc, new DataRequestMonitor<IRegisterGroupDMContext[]>(executor, rm) { |
| @Override |
| protected void handleSuccess() { |
| final IRegisterGroupDMContext[] groupsCtx = getData(); |
| assert (groupsCtx != null); |
| |
| final IRegisterGroupDMData[] groupsData = new IRegisterGroupDMData[groupsCtx.length]; |
| |
| final CountingRequestMonitor crm = new CountingRequestMonitor(executor, rm) { |
| @Override |
| protected void handleCompleted() { |
| rm.setData(groupsData); |
| rm.done(); |
| } |
| }; |
| |
| // Resolve all register group data |
| for (int i = 0; i < groupsCtx.length; i++) { |
| final int index = i; |
| fRegService.getRegisterGroupData(groupsCtx[index], new DataRequestMonitor<IRegisterGroupDMData>(executor, crm) { |
| @Override |
| protected void handleSuccess() { |
| groupsData[index] = getData(); |
| crm.done(); |
| } |
| }); |
| } |
| |
| crm.setDoneCount(groupsCtx.length); |
| } |
| }); |
| } |
| |
| private IRegisterDMContext[] getRegisters(int from, int to) throws Throwable { |
| MIStoppedEvent stoppedEvent = getInitialStoppedEvent(); |
| IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0); |
| final IRegisterDMContext[] regDMCs = getAllRegisters(frameDmc); |
| |
| // Shall not ask for more than is available |
| assertTrue(regDMCs.length > to); |
| |
| // Retrieve the register range |
| final IRegisterDMContext[] regRange = Arrays.copyOfRange(regDMCs, from, to); |
| |
| return regRange; |
| } |
| |
| private IRegisterGroupDMContext addDefaultUserGroup() throws Throwable { |
| // Define a subset of registers to create a register group |
| final IRegisterDMContext[] regInGroup = getRegisters(0, 4); |
| // Request the addition of the new group |
| addGroup(GROUP_X, regInGroup); |
| |
| // Retrieve the existing groups, expected and validated to 2 |
| IRegisterGroupDMContext[] groups = getRegisterGroups(2); |
| |
| // The groups are returned in reversed order to present latest created |
| // first i.e. index 0 |
| // Our new group shall be at the top then i.e. 0 |
| IFrameDMContext frameDmc = DMContexts.getAncestorOfType(regInGroup[0], IFrameDMContext.class); |
| CompositeDMContext compositeDmc = new CompositeDMContext(new IDMContext[]{groups[0], frameDmc}); |
| IRegisterDMContext[] readRegisters = getRegisters(compositeDmc); |
| |
| // Same objects and same order expected, although different parents |
| assertTrue(sameData(regInGroup, readRegisters, false)); |
| return groups[0]; |
| } |
| |
| private IRegisterGroupDMContext[] addRegisterGroups(int numberOfNewGroups) throws Throwable { |
| // Define a subset of registers to associate to the new register groups |
| final IRegisterDMContext[] regInGroup = getRegisters(0, 4); |
| for (int i = 0; i < numberOfNewGroups; i++) { |
| String groupName = proposeGroupName(); |
| addGroup(groupName, regInGroup); |
| } |
| |
| // Expected number of groups = Root + numberofNewGroups |
| return getRegisterGroups(1 + numberOfNewGroups); |
| } |
| |
| /** |
| * Check the register Data entry names are in the same order |
| */ |
| private boolean sameRegisterNames(IRegisterDMData[] regNames1, IRegisterDMData[] regNames2) { |
| boolean same = false; |
| if (regNames1.length == regNames2.length) { |
| for (int i = 0; i < regNames1.length; i++) { |
| if (regNames1[i].getName().equals(regNames2[i].getName())) { |
| continue; |
| } else { |
| // Found a different name, Not the same !! |
| return false; |
| } |
| } |
| |
| // All names matched !! |
| return true; |
| } |
| |
| return same; |
| } |
| |
| private boolean sameData(IRegisterDMContext[] regArrOne, IRegisterDMContext[] regArrTwo, boolean sameParentGroup) throws Throwable { |
| if (regArrOne.length != regArrTwo.length) { |
| return false; |
| } |
| |
| for (int i=0; i< regArrOne.length; i++) { |
| if (sameParentGroup) { |
| //same group parent expected |
| final IRegisterGroupDMContext parentGroupOne = DMContexts.getAncestorOfType(regArrOne[i], IRegisterGroupDMContext.class); |
| final IRegisterGroupDMContext parentGroupTwo = DMContexts.getAncestorOfType(regArrTwo[i], IRegisterGroupDMContext.class); |
| if(!parentGroupOne.equals(parentGroupTwo)) { |
| return false; |
| } |
| } |
| |
| //same data |
| IRegisterDMData dataOne = getRegisterData(regArrOne[i]); |
| IRegisterDMData dataTwo = getRegisterData(regArrTwo[i]); |
| |
| if (!dataOne.getName().equals(dataTwo.getName())) { |
| return false; |
| } |
| |
| //same value |
| FormattedValueDMData valueOne = getRegisterValue(regArrOne[i]); |
| FormattedValueDMData valueTwo = getRegisterValue(regArrTwo[i]); |
| if (!valueOne.getFormattedValue().equals(valueTwo.getFormattedValue())) { |
| return false; |
| } |
| } |
| |
| //All data is the same |
| return true; |
| } |
| |
| /** |
| * Resolve from proposed name to group sequence number e.g Group_5 -> 5 |
| */ |
| private int resolveGroupNameSequence(String groupName) { |
| int sequence = 0; |
| String[] strSequence = groupName.split("_"); |
| assertEquals(2, strSequence.length); |
| sequence = Integer.parseInt(strSequence[1]); |
| return sequence; |
| } |
| |
| } |