mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-03 22:35:43 +02:00
Bug 397715 - [memory][expressions] Make use of GDB 7.6 new
=memory-changed MI event Change-Id: I98c3cd273e185dfb1782527d7abd553351a163d9 Reviewed-on: https://git.eclipse.org/r/9662 Reviewed-by: Marc Khouzam <marc.khouzam@ericsson.com> IP-Clean: Marc Khouzam <marc.khouzam@ericsson.com> Tested-by: Marc Khouzam <marc.khouzam@ericsson.com>
This commit is contained in:
parent
7f1f78e77a
commit
0248aa4474
7 changed files with 551 additions and 19 deletions
|
@ -0,0 +1,165 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2013 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:
|
||||
* Marc Khouzam (Ericsson) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.service;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.eclipse.cdt.core.IAddress;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||
import org.eclipse.cdt.dsf.debug.service.IMemory;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
|
||||
import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
||||
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
|
||||
import org.eclipse.cdt.dsf.mi.service.MIMemory;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIConst;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MINotifyAsyncOutput;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.cdt.utils.Addr64;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
|
||||
/**
|
||||
* Memory service that uses the enhancements from GDB 7.6:
|
||||
* =memory-changed MI event
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
public class GDBMemory_7_6 extends GDBMemory_7_0 implements IEventListener {
|
||||
|
||||
private ICommandControlService fConnection;
|
||||
|
||||
public GDBMemory_7_6(DsfSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(final RequestMonitor requestMonitor) {
|
||||
super.initialize(
|
||||
new ImmediateRequestMonitor(requestMonitor) {
|
||||
@Override
|
||||
public void handleSuccess() {
|
||||
doInitialize(requestMonitor);
|
||||
}});
|
||||
}
|
||||
|
||||
private void doInitialize(final RequestMonitor requestMonitor) {
|
||||
register(new String[] { MIMemory.class.getName(),
|
||||
IMemory.class.getName(),
|
||||
GDBMemory_7_0.class.getName(),
|
||||
GDBMemory_7_6.class.getName()},
|
||||
new Hashtable<String, String>());
|
||||
|
||||
fConnection = getServicesTracker().getService(ICommandControlService.class);
|
||||
if (fConnection == null) {
|
||||
requestMonitor.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "CommandControl Service is not available")); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
fConnection.addEventListener(this);
|
||||
|
||||
requestMonitor.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown(final RequestMonitor requestMonitor) {
|
||||
fConnection.removeEventListener(this);
|
||||
unregister();
|
||||
super.shutdown(requestMonitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventReceived(Object output) {
|
||||
if (output instanceof MIOutput) {
|
||||
MIOOBRecord[] records = ((MIOutput)output).getMIOOBRecords();
|
||||
for (MIOOBRecord r : records) {
|
||||
if (r instanceof MINotifyAsyncOutput) {
|
||||
MINotifyAsyncOutput notifyOutput = (MINotifyAsyncOutput)r;
|
||||
String asyncClass = notifyOutput.getAsyncClass();
|
||||
// These events have been added with GDB 7.6
|
||||
if ("memory-changed".equals(asyncClass)) { //$NON-NLS-1$
|
||||
String groupId = null;
|
||||
String addr = null;
|
||||
int length = 0;
|
||||
|
||||
MIResult[] results = notifyOutput.getMIResults();
|
||||
for (int i = 0; i < results.length; i++) {
|
||||
String var = results[i].getVariable();
|
||||
MIValue val = results[i].getMIValue();
|
||||
if (var.equals("thread-group")) { //$NON-NLS-1$
|
||||
if (val instanceof MIConst) {
|
||||
groupId = ((MIConst)val).getString();
|
||||
}
|
||||
} else if (var.equals("addr")) { //$NON-NLS-1$
|
||||
if (val instanceof MIConst) {
|
||||
addr = ((MIConst)val).getString();
|
||||
}
|
||||
} else if (var.equals("len")) { //$NON-NLS-1$
|
||||
if (val instanceof MIConst) {
|
||||
try {
|
||||
String lenStr = ((MIConst)val).getString().trim();
|
||||
if (lenStr.startsWith("0x")) { //$NON-NLS-1$
|
||||
length = Integer.parseInt(lenStr.substring(2), 16);
|
||||
} else {
|
||||
length = Integer.parseInt(lenStr);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
} else if (var.equals("type")) { //$NON-NLS-1$
|
||||
if (val instanceof MIConst) {
|
||||
if ("code".equals(((MIConst)val).getString())) { //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMIProcesses procService = getServicesTracker().getService(IMIProcesses.class);
|
||||
if (procService != null && groupId != null && addr != null && length > 0) {
|
||||
IContainerDMContext containerDmc =
|
||||
procService.createContainerContextFromGroupId(fConnection.getContext(), groupId);
|
||||
|
||||
// Now refresh our memory cache, it case it contained this address. Don't have
|
||||
// it send the potential IMemoryChangedEvent as we will send it ourselves (see below).
|
||||
final IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(containerDmc, IMemoryDMContext.class);
|
||||
final IAddress address = new Addr64(addr);
|
||||
// The length returned by GDB is in bytes, while the memory cache expects
|
||||
// a count of number of addresses of 8 bytes.
|
||||
int count = length/8 + 1;
|
||||
getMemoryCache(memoryDMC).refreshMemory(memoryDMC, address, 0, 1, count, false,
|
||||
new RequestMonitor(getExecutor(), null) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
// Only once the memory cache is updated, we send the IMemoryChangedEvent. If we were to do it
|
||||
// earlier, the memory view may not show the updated value.
|
||||
//
|
||||
// We must always send this event when GDB reports a memory change because it can mean that
|
||||
// an expression or register has changed, and therefore we must notify the different views
|
||||
// and services of it. We cannot rely on this event to be sent by the memory cache after being
|
||||
// refreshed, because if the memory cache does not contain this address, it will not send
|
||||
// the event.
|
||||
getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, new IAddress[] { address }), getProperties());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008, 2012 Ericsson and others.
|
||||
* Copyright (c) 2008, 2013 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
|
||||
|
@ -12,6 +12,7 @@
|
|||
* Marc Khouzam (Ericsson) - Support for GDB 7.4 (Bug 367788)
|
||||
* Marc Khouzam (Ericsson) - Include IGDBHardware service for the multicore visualizer (Bug 335027)
|
||||
* Vladimir Prus (Mentor Graphics) - Support for OS resources.
|
||||
* Marc Khouzam (Ericsson) - Support for GDB 7.6 memory service
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.service;
|
||||
|
||||
|
@ -67,6 +68,8 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
|
|||
public static final String GDB_7_4_VERSION = "7.4"; //$NON-NLS-1$
|
||||
/** @since 4.2*/
|
||||
public static final String GDB_7_5_VERSION = "7.5"; //$NON-NLS-1$
|
||||
/** @since 4.2*/
|
||||
public static final String GDB_7_6_VERSION = "7.5.50"; //$NON-NLS-1$
|
||||
|
||||
private final String fVersion;
|
||||
|
||||
|
@ -172,6 +175,10 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
|
|||
|
||||
@Override
|
||||
protected IMemory createMemoryService(DsfSession session) {
|
||||
if (GDB_7_6_VERSION.compareTo(fVersion) <= 0) {
|
||||
return new GDBMemory_7_6(session);
|
||||
}
|
||||
|
||||
if (GDB_7_0_VERSION.compareTo(fVersion) <= 0) {
|
||||
return new GDBMemory_7_0(session);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
|||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.ICachingService;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IMemory;
|
||||
|
@ -92,7 +93,8 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
|
|||
// Map of memory caches
|
||||
private Map<IMemoryDMContext, MIMemoryCache> fMemoryCaches;
|
||||
|
||||
private MIMemoryCache getMemoryCache(IMemoryDMContext memoryDMC) {
|
||||
/** @since 4.2 */
|
||||
protected MIMemoryCache getMemoryCache(IMemoryDMContext memoryDMC) {
|
||||
MIMemoryCache cache = fMemoryCaches.get(memoryDMC);
|
||||
if (cache == null) {
|
||||
cache = new MIMemoryCache();
|
||||
|
@ -490,12 +492,19 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @nooverride This method is not intended to be re-implemented or extended by clients.
|
||||
* @noreference This method is not intended to be referenced by clients.
|
||||
*/
|
||||
@DsfServiceEventHandler
|
||||
/**
|
||||
* @deprecated Replaced by the generic {@link #eventDispatched(IExpressionChangedDMEvent)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void eventDispatched(ExpressionChangedEvent e) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @noreference This method is not intended to be referenced by clients.
|
||||
* @since 4.2
|
||||
*/
|
||||
@DsfServiceEventHandler
|
||||
public void eventDispatched(IExpressionChangedDMEvent e) {
|
||||
|
||||
// Get the context and expression service handle
|
||||
final IExpressionDMContext context = e.getDMContext();
|
||||
|
@ -518,7 +527,7 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
|
|||
address = new Addr64(expAddress.getValue());
|
||||
|
||||
final IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, IMemoryDMContext.class);
|
||||
getMemoryCache(memoryDMC).refreshMemory(memoryDMC, address, 0, 1, count,
|
||||
getMemoryCache(memoryDMC).refreshMemory(memoryDMC, address, 0, 1, count, true,
|
||||
new RequestMonitor(getExecutor(), null));
|
||||
}
|
||||
});
|
||||
|
@ -629,7 +638,8 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
|
|||
// MIMemoryCache
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private class MIMemoryCache {
|
||||
/** @since 4.2 */
|
||||
protected class MIMemoryCache {
|
||||
// The memory cache data structure
|
||||
private SortedMemoryBlockList fMemoryBlockList;
|
||||
|
||||
|
@ -965,10 +975,12 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
|
|||
* @param offset
|
||||
* @param word_size
|
||||
* @param count
|
||||
* @param sendMemoryEvent Indicates if a IMemoryChangedEvent should be sent if the memory cache has changed.
|
||||
* @param rm
|
||||
*/
|
||||
public void refreshMemory(final IMemoryDMContext memoryDMC, final IAddress address,
|
||||
final long offset, final int word_size, final int count, final RequestMonitor rm)
|
||||
final long offset, final int word_size, final int count, final boolean sendMemoryEvent,
|
||||
final RequestMonitor rm)
|
||||
{
|
||||
// Check if we already cache part of this memory area (which means it
|
||||
// is used by a memory service client that will have to be updated)
|
||||
|
@ -983,16 +995,10 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
|
|||
rm.done();
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the data for the MemoryChangedEvent
|
||||
final IAddress[] addresses = new IAddress[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
addresses[i] = address.add(i);
|
||||
}
|
||||
|
||||
// Read the corresponding memory block
|
||||
fCommandCache.reset();
|
||||
readMemoryBlock(memoryDMC, address, 0, 1, count,
|
||||
readMemoryBlock(memoryDMC, address, offset, word_size, count,
|
||||
new DataRequestMonitor<MemoryByte[]>(getExecutor(), rm) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
|
@ -1006,8 +1012,15 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
|
|||
}
|
||||
}
|
||||
if (blocksDiffer) {
|
||||
updateMemoryCache(address, count, newBlock);
|
||||
getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties());
|
||||
updateMemoryCache(address.add(offset), count, newBlock);
|
||||
if (sendMemoryEvent) {
|
||||
// Send the MemoryChangedEvent
|
||||
final IAddress[] addresses = new IAddress[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
addresses[i] = address.add(offset + i);
|
||||
}
|
||||
getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties());
|
||||
}
|
||||
}
|
||||
rm.done();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int testMemoryChanges() {
|
||||
int i = 8;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("Running ConsoleSyncTestApp\n");
|
||||
|
||||
testMemoryChanges();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2013 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:
|
||||
* Marc Khouzam (Ericsson) - Initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_6;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.cdt.core.IAddress;
|
||||
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IMemory;
|
||||
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
|
||||
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
||||
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
|
||||
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
|
||||
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner;
|
||||
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase;
|
||||
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.tests.ITestConstants;
|
||||
import org.eclipse.debug.core.model.MemoryByte;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* This test case verifies that different commands issued from the
|
||||
* GDB console cause proper updating within the CDT views.
|
||||
*/
|
||||
@RunWith(BackgroundRunner.class)
|
||||
public class GDBConsoleSynchronizingTest_7_6 extends BaseTestCase {
|
||||
|
||||
final static private int DEFAULT_TIMEOUT = 1000;
|
||||
final static private TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;
|
||||
|
||||
private DsfSession fSession;
|
||||
private DsfServicesTracker fServicesTracker;
|
||||
private IGDBControl fCommandControl;
|
||||
private IMemory fMemoryService;
|
||||
private IExpressions fExprService;
|
||||
|
||||
private List<IDMEvent<? extends IDMContext>> fEventsReceived = new ArrayList<IDMEvent<? extends IDMContext>>();
|
||||
|
||||
@Override
|
||||
protected void setGdbVersion() {
|
||||
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_6);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setLaunchAttributes() {
|
||||
super.setLaunchAttributes();
|
||||
|
||||
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, "data/launch/bin/ConsoleSyncTestApp.exe");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doBeforeTest() throws Exception {
|
||||
super.doBeforeTest();
|
||||
|
||||
fSession = getGDBLaunch().getSession();
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId());
|
||||
Assert.assertTrue(fServicesTracker != null);
|
||||
|
||||
fCommandControl = fServicesTracker.getService(IGDBControl.class);
|
||||
Assert.assertTrue(fCommandControl != null);
|
||||
|
||||
fMemoryService = fServicesTracker.getService(IMemory.class);
|
||||
Assert.assertTrue(fMemoryService != null);
|
||||
|
||||
fExprService = fServicesTracker.getService(IExpressions.class);
|
||||
Assert.assertTrue(fExprService != null);
|
||||
|
||||
// Register to breakpoint events
|
||||
fSession.addServiceEventListener(GDBConsoleSynchronizingTest_7_6.this, null);
|
||||
}
|
||||
};
|
||||
fSession.getExecutor().submit(runnable).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterTest() throws Exception {
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fSession.removeServiceEventListener(GDBConsoleSynchronizingTest_7_6.this);
|
||||
}
|
||||
};
|
||||
fSession.getExecutor().submit(runnable).get();
|
||||
fEventsReceived.clear();
|
||||
fServicesTracker.dispose();
|
||||
super.doAfterTest();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Start of tests
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* This test verifies that setting a variable from the console
|
||||
* using the set command will properly trigger a DSF event to
|
||||
* indicate the change. This test makes sure the value that
|
||||
* changes is in the memory cache also.
|
||||
*/
|
||||
@Test
|
||||
public void testSettingVariableWithSetWithMemory() throws Throwable {
|
||||
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testMemoryChanges");
|
||||
|
||||
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
|
||||
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "i");
|
||||
|
||||
// Read the memory that will change first, or else there will be no event for it
|
||||
Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() {
|
||||
@Override
|
||||
protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) {
|
||||
fExprService.getExpressionAddressData(exprDmc, rm);
|
||||
}
|
||||
};
|
||||
|
||||
fSession.getExecutor().execute(query);
|
||||
IExpressionDMAddress data = query.get();
|
||||
|
||||
IMemoryDMContext memoryDmc = DMContexts.getAncestorOfType(frameDmc, IMemoryDMContext.class);
|
||||
readMemory(memoryDmc, data.getAddress(), data.getSize());
|
||||
|
||||
fEventsReceived.clear();
|
||||
queueConsoleCommand("set variable i=100");
|
||||
|
||||
IMemoryChangedEvent memoryEvent = waitForEvent(IMemoryChangedEvent.class);
|
||||
assertEquals(1, memoryEvent.getAddresses().length);
|
||||
assertEquals(data.getAddress(), memoryEvent.getAddresses()[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verifies that setting a variable from the console
|
||||
* using the set command will properly trigger a DSF event to
|
||||
* indicate the change, when the address is not in the memory cache.
|
||||
*/
|
||||
@Test
|
||||
public void testSettingVariableWithSet() throws Throwable {
|
||||
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testMemoryChanges");
|
||||
|
||||
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
|
||||
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "i");
|
||||
|
||||
// Read the memory that will change first, or else there will be no event for it
|
||||
Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() {
|
||||
@Override
|
||||
protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) {
|
||||
fExprService.getExpressionAddressData(exprDmc, rm);
|
||||
}
|
||||
};
|
||||
|
||||
fSession.getExecutor().execute(query);
|
||||
IExpressionDMAddress data = query.get();
|
||||
|
||||
fEventsReceived.clear();
|
||||
queueConsoleCommand("set variable i=100");
|
||||
|
||||
IMemoryChangedEvent memoryEvent = waitForEvent(IMemoryChangedEvent.class);
|
||||
assertEquals(1, memoryEvent.getAddresses().length);
|
||||
assertEquals(data.getAddress(), memoryEvent.getAddresses()[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verifies that setting a variable from the console
|
||||
* using the print command will properly trigger a DSF event
|
||||
* to indicate the change.
|
||||
*/
|
||||
@Test
|
||||
public void testSettingVariableWithPrint() throws Throwable {
|
||||
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testMemoryChanges");
|
||||
|
||||
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
|
||||
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "i");
|
||||
|
||||
// Read the memory that will change first, or else there will be no event for it
|
||||
Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() {
|
||||
@Override
|
||||
protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) {
|
||||
fExprService.getExpressionAddressData(exprDmc, rm);
|
||||
}
|
||||
};
|
||||
|
||||
fSession.getExecutor().execute(query);
|
||||
IExpressionDMAddress data = query.get();
|
||||
|
||||
fEventsReceived.clear();
|
||||
queueConsoleCommand("print i=100");
|
||||
|
||||
IMemoryChangedEvent memoryEvent = waitForEvent(IMemoryChangedEvent.class);
|
||||
assertEquals(1, memoryEvent.getAddresses().length);
|
||||
assertEquals(data.getAddress(), memoryEvent.getAddresses()[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verifies that setting a memory location from the
|
||||
* console will properly trigger a DSF event to indicate the change.
|
||||
*/
|
||||
@Test
|
||||
public void testSettingMemory() throws Throwable {
|
||||
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testMemoryChanges");
|
||||
|
||||
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
|
||||
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "i");
|
||||
|
||||
// Read the memory that will change first, or else there will be no event for it
|
||||
Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() {
|
||||
@Override
|
||||
protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) {
|
||||
fExprService.getExpressionAddressData(exprDmc, rm);
|
||||
}
|
||||
};
|
||||
|
||||
fSession.getExecutor().execute(query);
|
||||
IExpressionDMAddress data = query.get();
|
||||
|
||||
fEventsReceived.clear();
|
||||
queueConsoleCommand("set {int}&i=100");
|
||||
|
||||
IMemoryChangedEvent memoryEvent = waitForEvent(IMemoryChangedEvent.class);
|
||||
assertEquals(1, memoryEvent.getAddresses().length);
|
||||
assertEquals(data.getAddress(), memoryEvent.getAddresses()[0]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// End of tests
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@DsfServiceEventHandler
|
||||
public void eventDispatched(IDMEvent<? extends IDMContext> e) {
|
||||
synchronized(this) {
|
||||
fEventsReceived.add(e);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
private MemoryByte[] readMemory(final IMemoryDMContext dmc, final IAddress address, final int count)
|
||||
throws Throwable
|
||||
{
|
||||
Query<MemoryByte[]> query = new Query<MemoryByte[]>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<MemoryByte[]> rm) {
|
||||
fMemoryService.getMemory(dmc, address, 0, 1, count, rm);
|
||||
}
|
||||
};
|
||||
fSession.getExecutor().execute(query);
|
||||
return query.get(DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
|
||||
}
|
||||
|
||||
private void queueConsoleCommand(String command) throws Throwable {
|
||||
queueConsoleCommand(command, DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
|
||||
}
|
||||
|
||||
private void queueConsoleCommand(final String command, int timeout, TimeUnit unit) throws Throwable {
|
||||
Query<MIInfo> query = new Query<MIInfo>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<MIInfo> rm) {
|
||||
fCommandControl.queueCommand(
|
||||
fCommandControl.getCommandFactory().createMIInterpreterExecConsole(
|
||||
fCommandControl.getContext(),
|
||||
command),
|
||||
rm);
|
||||
}
|
||||
};
|
||||
fSession.getExecutor().execute(query);
|
||||
query.get(timeout, unit);
|
||||
}
|
||||
|
||||
private <V extends IDMEvent<? extends IDMContext>> V waitForEvent(Class<V> eventType) throws Exception {
|
||||
return waitForEvent(eventType, DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <V extends IDMEvent<? extends IDMContext>> V waitForEvent(Class<V> eventType, int timeout) throws Exception {
|
||||
IDMEvent<?> event = getEvent(eventType);
|
||||
if (event == null) {
|
||||
synchronized(this) {
|
||||
try {
|
||||
wait(timeout);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
event = getEvent(eventType);
|
||||
if (event == null) {
|
||||
throw new Exception(String.format("Timed out waiting for '%s' to occur.", eventType.getName()));
|
||||
}
|
||||
}
|
||||
return (V)event;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private synchronized <V extends IDMEvent<? extends IDMContext>> V getEvent(Class<V> eventType) {
|
||||
for (IDMEvent<?> e : fEventsReceived) {
|
||||
if (eventType.isAssignableFrom(e.getClass())) {
|
||||
fEventsReceived.remove(e);
|
||||
return (V)e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -48,6 +48,7 @@ import org.junit.runners.Suite;
|
|||
GDBMultiNonStopRunControlTest_7_6.class,
|
||||
Suite_Sessionless_Tests.class,
|
||||
GDBConsoleBreakpointsTest_7_6.class,
|
||||
GDBConsoleSynchronizingTest_7_6.class,
|
||||
/* Add your test class here */
|
||||
})
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.junit.runners.Suite;
|
|||
Suite_Sessionless_Tests.class,
|
||||
GDBConsoleBreakpointsTest_7_6.class,
|
||||
TraceFileTest_7_6.class,
|
||||
GDBConsoleSynchronizingTest_7_6.class,
|
||||
/* Add your test class here */
|
||||
})
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue