1
/*******************************************************************************
2
* Copyright (c) 2009, 2010 Ericsson and others.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* Ericsson - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.cdt.tests.dsf.gdb.tests;
14
import static org.junit.Assert.assertEquals;
15
import static org.junit.Assert.assertTrue;
17
import java.util.Arrays;
18
import java.util.LinkedList;
19
import java.util.List;
21
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
22
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
23
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
24
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
25
import org.eclipse.cdt.dsf.concurrent.Query;
26
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
27
import org.eclipse.cdt.dsf.datamodel.CompositeDMContext;
28
import org.eclipse.cdt.dsf.datamodel.DMContexts;
29
import org.eclipse.cdt.dsf.datamodel.IDMContext;
30
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
31
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
32
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
33
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
34
import org.eclipse.cdt.dsf.debug.service.IRegisters;
35
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
36
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData;
37
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
38
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData;
39
import org.eclipse.cdt.dsf.debug.service.IRunControl;
40
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
41
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
42
import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
43
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
44
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
45
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
46
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
47
import org.eclipse.cdt.dsf.mi.service.MIProcesses;
48
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
49
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
50
import org.eclipse.cdt.dsf.service.DsfSession;
51
import org.eclipse.cdt.tests.dsf.gdb.framework.AsyncCompletionWaitor;
52
import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner;
53
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase;
54
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil;
55
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
56
import org.eclipse.core.runtime.Platform;
57
import org.junit.After;
58
import org.junit.Assert;
59
import org.junit.Before;
60
import org.junit.BeforeClass;
61
import org.junit.Ignore;
62
import org.junit.Test;
63
import org.junit.runner.RunWith;
65
@RunWith(BackgroundRunner.class)
67
public class MIRegistersTest extends BaseTestCase {
69
protected List<String> get_X86_REGS() {
70
List<String> list = new LinkedList<String>(Arrays.asList("eax","ecx","edx","ebx","esp","ebp","esi","edi","eip","eflags",
71
"cs","ss","ds","es","fs","gs","st0","st1","st2","st3",
72
"st4","st5","st6","st7","fctrl","fstat","ftag","fiseg","fioff","foseg",
73
"fooff","fop","xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7",
74
"mxcsr","orig_eax","mm0","mm1","mm2","mm3","mm4","mm5","mm6","mm7"));
75
// On Windows, gdb doesn't report "orig_eax" as a register. Apparently it does on Linux
76
if (Platform.getOS().equals(Platform.OS_WIN32)) {
77
list.remove("orig_eax");
85
private static final String EXEC_PATH = "data/launch/bin/";
87
* Name of the executable
89
private static final String EXEC_NAME = "MultiThread.exe";
90
private static final String SRC_NAME = "MultiThread.cc";
92
// Will be used to wait for asynchronous call to complete
93
//private final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor();
94
private DsfSession fSession;
95
private DsfServicesTracker fServicesTracker;
96
private IContainerDMContext fContainerDmc;
97
private IRegisters fRegService;
98
private IRunControl fRunControl;
101
public void init() throws Exception {
102
fSession = getGDBLaunch().getSession();
104
Runnable runnable = new Runnable() {
106
// We obtain the services we need after the new
107
// launch has been performed
108
fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId());
110
ICommandControlService commandControl = fServicesTracker.getService(ICommandControlService.class);
111
IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class);
112
IProcessDMContext procDmc = procService.createProcessContext(commandControl.getContext(), MIProcesses.UNIQUE_GROUP_ID);
113
fContainerDmc = procService.createContainerContext(procDmc, MIProcesses.UNIQUE_GROUP_ID);
115
fRegService = fServicesTracker.getService(IRegisters.class);
116
fRunControl = fServicesTracker.getService(IRunControl.class);
119
fSession.getExecutor().submit(runnable).get();
123
public static void beforeClassMethod() {
124
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME,
125
EXEC_PATH + EXEC_NAME);
130
public void tearDown() {
131
fServicesTracker.dispose();
136
* This is a common support method which gets the Register Group Information
139
private IRegisterGroupDMContext getRegisterGroup() throws Throwable {
140
final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor();
142
final DataRequestMonitor<IRegisterGroupDMContext[]> regGroupDone =
143
new DataRequestMonitor<IRegisterGroupDMContext[]>(fRegService.getExecutor(), null) {
145
protected void handleCompleted() {
147
fWait.setReturnInfo(getData());
150
fWait.waitFinished(getStatus());
154
fRegService.getExecutor().submit(new Runnable() {
156
fRegService.getRegisterGroups(fContainerDmc, regGroupDone);
160
fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER);
161
assertTrue(fWait.getMessage(), fWait.isOK());
163
IRegisterGroupDMContext[] regGroupsDMCs = (IRegisterGroupDMContext[])fWait.getReturnInfo();
164
assertTrue("There was more than one register group (" + regGroupsDMCs.length + ")", //$NON-NLS-1$
165
regGroupsDMCs.length == 1 );
168
return(regGroupsDMCs[0]);
172
* This is a common support method which gets the Registers names.
175
private IRegisterDMContext[] getRegisters(final IFrameDMContext frameDmc) throws Throwable {
176
final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor();
177
final IRegisterGroupDMContext regGroupsDMC = getRegisterGroup();
179
fRegService.getExecutor().submit(new Runnable() {
181
fRegService.getRegisters(
182
new CompositeDMContext(new IDMContext[] { regGroupsDMC, frameDmc} ),
183
new DataRequestMonitor<IRegisterDMContext[]>(fRegService.getExecutor(), null) {
185
protected void handleCompleted() {
187
fWait.setReturnInfo(getData());
190
fWait.waitFinished(getStatus());
196
fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER);
197
assertTrue(fWait.getMessage(), fWait.isOK());
199
IRegisterDMContext[] regContexts = (IRegisterDMContext[]) fWait.getReturnInfo();
203
assertEquals("Wrong number of registers", get_X86_REGS().size(), regContexts.length);
208
/*************************************************************************
210
* The tests for the register service.
212
*************************************************************************/
215
public void getRegisterGroups() throws Throwable {
216
final IRegisterGroupDMContext regGroupsDMC = getRegisterGroup();
218
Query<IRegisterGroupDMData> query = new Query<IRegisterGroupDMData>() {
220
protected void execute(DataRequestMonitor<IRegisterGroupDMData> rm) {
221
fRegService.getRegisterGroupData(regGroupsDMC, rm);
224
fSession.getExecutor().execute(query);
226
IRegisterGroupDMData data = query.get();
228
assertTrue("The name of the main group should be: General Registers instead of: " +
230
data.getName().equals("General Registers"));
234
public void getRegistersLength() throws Throwable {
235
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
236
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
237
final IRegisterDMContext[] regDMCs = getRegisters(frameDmc);
238
assertEquals("Wrong number of registers", get_X86_REGS().size(), regDMCs.length);
242
public void getRegisters() throws Throwable {
243
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
244
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
245
final IRegisterDMContext[] regDMCs = getRegisters(frameDmc);
246
List<String> regNames = get_X86_REGS();
248
Query<IRegisterDMData[]> query = new Query<IRegisterDMData[]>() {
250
protected void execute(DataRequestMonitor<IRegisterDMData[]> rm) {
251
final IRegisterDMData[] datas = new IRegisterDMData[regDMCs.length];
253
final CountingRequestMonitor countingRm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), rm);
254
countingRm.setDoneCount(regDMCs.length);
255
for (int i = 0; i < regDMCs.length; i++) {
257
fRegService.getRegisterData(
259
new DataRequestMonitor<IRegisterDMData>(ImmediateExecutor.getInstance(), countingRm) {
261
protected void handleSuccess() {
262
datas[index] = getData();
271
fSession.getExecutor().execute(query);
273
IRegisterDMData[] datas = query.get();
275
for(IRegisterDMData data: datas){
276
String regName = data.getName();
277
Assert.assertFalse("GDB does not support register name: " + regName, !regNames.contains(regName));
281
private String getModelDataForRegisterDataValue(IFrameDMContext frameDmc, String format, int regNo) throws Throwable {
282
final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
284
final IRegisterDMContext[] regDMCs = getRegisters(frameDmc);
285
final FormattedValueDMContext valueDmc = fRegService.getFormattedValueContext(regDMCs[regNo], format);
287
final DataRequestMonitor<FormattedValueDMData> regRm =
288
new DataRequestMonitor<FormattedValueDMData>(fRegService.getExecutor(), null) {
290
protected void handleCompleted() {
292
wait.setReturnInfo(getData());
295
wait.waitFinished(getStatus());
299
fRegService.getExecutor().submit(new Runnable() {
301
fRegService.getFormattedExpressionValue(valueDmc, regRm);
305
wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER);
306
assertTrue(wait.getMessage(), wait.isOK());
309
FormattedValueDMData data = (FormattedValueDMData)wait.getReturnInfo();
310
return data.getFormattedValue();
314
private static String REGISTER_VALUE = "";
316
public void getModelDataForRegisterDataValueInDifferentNumberFormats() throws Throwable {
317
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
318
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
319
String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, 0);
320
REGISTER_VALUE = val;
321
assertTrue("Register Value is not in NATURAL format " , Integer.parseInt(val)== Integer.parseInt(REGISTER_VALUE));
323
val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, 0);
324
assertTrue("Register Value is not in HEX_FORMAT " ,val.startsWith("0x"));
326
val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, 0);
327
Assert.assertEquals("Register Value is not in BINARY_FORMAT ", Integer.toBinaryString(Integer.parseInt(REGISTER_VALUE)), val);
329
val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.DECIMAL_FORMAT , 0);
330
Assert.assertEquals("Register Value is not in DECIMAL_FORMAT", Integer.parseInt(REGISTER_VALUE), Integer.parseInt(val));
332
val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, 0);
333
assertTrue("Register Value is not in OCTAL_FORMAT " ,val.startsWith("0"));
338
public void compareRegisterForMultipleExecutionContexts() throws Throwable {
340
// Run past the line that creates a thread and past the sleep that
341
// follows it. This is a bit tricky because the code that creates the
342
// thread is conditional depending on environment. Run to the printf
343
// before it (which is common), then do step operations over the
344
// non-common code (but same number of lines)
345
SyncUtil.runToLine(SRC_NAME, Integer.toString(MIRunControlTest.LINE_MAIN_PRINTF));
346
SyncUtil.step(StepType.STEP_OVER); // over the printf
347
SyncUtil.step(StepType.STEP_OVER); // over the create-thread call
348
MIStoppedEvent stoppedEvent = SyncUtil.step(StepType.STEP_OVER, TestsPlugin.massageTimeout(2000)); // over the one second sleep
350
// Get the thread IDs
351
final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(stoppedEvent.getDMContext(), IContainerDMContext.class);
353
final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
354
final DataRequestMonitor<IExecutionDMContext[]> drm =
355
new DataRequestMonitor<IExecutionDMContext[]>(fRegService.getExecutor(), null) {
357
protected void handleCompleted() {
359
wait.setReturnInfo(getData());
361
wait.waitFinished(getStatus());
365
fRegService.getExecutor().submit(new Runnable() {
367
fRunControl.getExecutionContexts(containerDmc, drm);
370
wait.waitUntilDone(TestsPlugin.massageTimeout(5000));
371
Assert.assertTrue(wait.getMessage(), wait.isOK());
373
IExecutionDMContext[] ctxts = (IExecutionDMContext[])wait.getReturnInfo();
376
Assert.assertNotNull(ctxts);
377
Assert.assertTrue(ctxts.length > 1);
379
int tid1 = ((IMIExecutionDMContext)ctxts[0]).getThreadId();
380
int tid2 = ((IMIExecutionDMContext)ctxts[1]).getThreadId();
382
// Get execution context to thread 2
383
IExecutionDMContext execDmc = SyncUtil.createExecutionContext(containerDmc, tid2);
384
IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(execDmc, 0);
386
String thread2RegVal0 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 0);
387
String thread2RegVal1 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 1);
388
String thread2RegVal2 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 2);
389
String thread2RegVal3 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 3);
390
String thread2RegVal4 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 4);
391
String thread2RegVal5 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 5);
393
// Get execution context to thread 1
394
execDmc = SyncUtil.createExecutionContext(containerDmc, tid1);
395
IFrameDMContext frameDmc1 = SyncUtil.getStackFrame(execDmc, 0);
396
getModelDataForRegisterDataValue(frameDmc1, IFormattedValues.NATURAL_FORMAT, 0);
398
// Re-set the execution context to 2 and Fetch from the Cache
399
String dupliThread2RegVal0 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 0);
400
String dupliThread2RegVal1 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 1);
401
String dupliThread2RegVal2 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 2);
402
String dupliThread2RegVal3 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 3);
403
String dupliThread2RegVal4 = getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 4);
404
String dupliThread2RegVal5= getModelDataForRegisterDataValue(frameDmc2, IFormattedValues.NATURAL_FORMAT, 5);
406
// If Values not equal , then context haven't been re-set properly
407
assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal0.equals(dupliThread2RegVal0));
408
assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal1.equals(dupliThread2RegVal1));
409
assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal2.equals(dupliThread2RegVal2));
410
assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal3.equals(dupliThread2RegVal3));
411
assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal4.equals(dupliThread2RegVal4));
412
assertTrue("Multiple context not working. Execution Context is not reset to 2", thread2RegVal5.equals(dupliThread2RegVal5));
416
private void writeRegister(IFrameDMContext frameDmc, final int regIndex, final String regValue, final String formatId) throws Throwable {
417
final AsyncCompletionWaitor fWait = new AsyncCompletionWaitor();
419
final IRegisterDMContext[] regDMCs = getRegisters(frameDmc);
421
fRegService.getExecutor().submit(new Runnable() {
423
fRegService.writeRegister(
426
new RequestMonitor(fRegService.getExecutor(), null) {
428
protected void handleCompleted() {
429
fWait.waitFinished(getStatus());
436
fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER);
442
public void writeRegisterNaturalFormat() throws Throwable{
443
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
444
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
445
String regValue = "10";
447
writeRegister(frameDmc, 3, regValue, IFormattedValues.NATURAL_FORMAT);
448
String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.NATURAL_FORMAT, regIndex);
449
assertTrue("Failed writing register. New value should have been " + regValue, regValue.equals(val));
453
public void writeRegisterHEXFormat() throws Throwable{
454
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
455
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
456
String regValue = "0x10";
458
writeRegister(frameDmc, 3, regValue, IFormattedValues.HEX_FORMAT);
459
String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.HEX_FORMAT, regIndex);
460
assertTrue("Failed writing register. New value should have been " + regValue, regValue.equals(val));
465
public void writeRegisterBinaryFormat() throws Throwable{
466
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
467
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
468
//String regValue = "0100101001";
469
String regValue = "10";
471
writeRegister(frameDmc, 3, regValue, IFormattedValues.BINARY_FORMAT);
472
String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.BINARY_FORMAT, regIndex);
473
assertTrue("Failed writing register. New value should have been " + regValue + " instead of " + val, regValue.equals(val));
477
public void writeRegisterOctalFormat() throws Throwable{
478
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
479
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
480
//String regValue = "10";
481
String regValue = "012";
483
writeRegister(frameDmc, 3, regValue, IFormattedValues.OCTAL_FORMAT);
484
String val = getModelDataForRegisterDataValue(frameDmc, IFormattedValues.OCTAL_FORMAT, regIndex);
485
assertTrue("Failed writing register. New value should have been " + regValue + "instead of " + val, regValue.equals(val));