mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-22 06:02:11 +02:00
Bug 431627 - [mem] Need additional API to extend support for memory
spaces Change-Id: I775f443927ddd326e5aab5c0e9243cd818edde41 Signed-off-by: Alvaro Sanchez-Leon <alvsan09@gmail.com> Reviewed-on: https://git.eclipse.org/r/24994 Reviewed-by: Marc Khouzam <marc.khouzam@ericsson.com> Tested-by: Hudson CI Tested-by: Marc Khouzam <marc.khouzam@ericsson.com>
This commit is contained in:
parent
fa5de3be3b
commit
ddb8ab8708
6 changed files with 209 additions and 215 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2010 Wind River Systems and others.
|
* Copyright (c) 2010, 2014 Wind River Systems and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -7,6 +7,8 @@
|
||||||
*
|
*
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* Wind River Systems - initial implementation
|
* Wind River Systems - initial implementation
|
||||||
|
* Anders Dahlberg (Ericsson) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
|
* Alvaro Sanchez-Leon (Ericsson) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.gdb;
|
package org.eclipse.cdt.dsf.gdb;
|
||||||
|
|
||||||
|
@ -136,7 +138,7 @@ public class GDBTypeParser {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sb.insert(0, ' ');
|
sb.insert(0, ' ');
|
||||||
sb.insert(0, gdbType.nameType);
|
sb.insert(0, gdbType.getTypeName());
|
||||||
gdbType = null;
|
gdbType = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,9 +281,12 @@ public class GDBTypeParser {
|
||||||
insertingChild(kind, 0);
|
insertingChild(kind, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertingChild(int kind, int d) {
|
/**
|
||||||
|
* @since 4.4
|
||||||
|
*/
|
||||||
|
protected void insertingChild(int kind, int d) {
|
||||||
if (gdbDerivedType == null) {
|
if (gdbDerivedType == null) {
|
||||||
gdbDerivedType = new GDBDerivedType(genericType, kind, d);
|
gdbDerivedType = createGDBDerivedType(genericType, kind, d);
|
||||||
} else {
|
} else {
|
||||||
GDBDerivedType dType = gdbDerivedType;
|
GDBDerivedType dType = gdbDerivedType;
|
||||||
GDBType gdbType = gdbDerivedType.getChild();
|
GDBType gdbType = gdbDerivedType.getChild();
|
||||||
|
@ -289,7 +294,7 @@ public class GDBTypeParser {
|
||||||
dType = (GDBDerivedType)gdbType;
|
dType = (GDBDerivedType)gdbType;
|
||||||
gdbType = dType.getChild();
|
gdbType = dType.getChild();
|
||||||
}
|
}
|
||||||
gdbType = new GDBDerivedType(gdbType, kind, d);
|
gdbType = createGDBDerivedType(gdbType, kind, d);
|
||||||
dType.setChild(gdbType);
|
dType.setChild(gdbType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,6 +465,13 @@ public class GDBTypeParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.4
|
||||||
|
*/
|
||||||
|
protected GDBDerivedType createGDBDerivedType(GDBType c, int t, int dim) {
|
||||||
|
return new GDBDerivedType(c, t, dim);
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
GDBTypeParser parser = new GDBTypeParser();
|
GDBTypeParser parser = new GDBTypeParser();
|
||||||
|
|
|
@ -8,37 +8,31 @@
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* Texas Instruments, Freescale Semiconductor - initial API and implementation
|
* Texas Instruments, Freescale Semiconductor - initial API and implementation
|
||||||
* Alvaro Sanchez-Leon (Ericsson AB) - [Memory] Support 16 bit addressable size (Bug 426730)
|
* Alvaro Sanchez-Leon (Ericsson AB) - [Memory] Support 16 bit addressable size (Bug 426730)
|
||||||
|
* Anders Dahlberg (Ericsson) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
|
* Alvaro Sanchez-Leon (Ericsson AB) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.gdb.internal.memory;
|
package org.eclipse.cdt.dsf.gdb.internal.memory;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
|
|
||||||
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock;
|
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
|
||||||
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
|
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
|
||||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
|
||||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
|
||||||
import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
|
import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlock;
|
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlock;
|
||||||
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval;
|
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IMemory;
|
|
||||||
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IMemorySpaces;
|
|
||||||
import org.eclipse.cdt.dsf.debug.service.IMemorySpaces.IMemorySpaceDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IMemorySpaces.IMemorySpaceDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
||||||
import org.eclipse.cdt.dsf.gdb.service.IGDBMemory;
|
import org.eclipse.cdt.dsf.gdb.service.IGDBMemory;
|
||||||
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
|
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
|
||||||
import org.eclipse.cdt.utils.Addr64;
|
|
||||||
import org.eclipse.core.runtime.IStatus;
|
import org.eclipse.core.runtime.IStatus;
|
||||||
import org.eclipse.core.runtime.Status;
|
import org.eclipse.core.runtime.Status;
|
||||||
import org.eclipse.debug.core.DebugEvent;
|
import org.eclipse.debug.core.DebugEvent;
|
||||||
import org.eclipse.debug.core.DebugException;
|
import org.eclipse.debug.core.DebugException;
|
||||||
import org.eclipse.debug.core.DebugPlugin;
|
import org.eclipse.debug.core.DebugPlugin;
|
||||||
import org.eclipse.debug.core.model.MemoryByte;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A specialization of the DSF memory block implementation supporting memory
|
* A specialization of the DSF memory block implementation supporting memory
|
||||||
|
@ -59,6 +53,18 @@ public class GdbMemoryBlock extends DsfMemoryBlock implements IMemorySpaceAwareM
|
||||||
super(retrieval, context, modelId, expression, address, word_size, length);
|
super(retrieval, context, modelId, expression, address, word_size, length);
|
||||||
fMemorySpaceID = (memorySpaceID != null && memorySpaceID.length() > 0) ? memorySpaceID : null;
|
fMemorySpaceID = (memorySpaceID != null && memorySpaceID.length() > 0) ? memorySpaceID : null;
|
||||||
assert memorySpaceID == null || memorySpaceID.length() > 0; // callers shouldn't be passing in an empty string
|
assert memorySpaceID == null || memorySpaceID.length() > 0; // callers shouldn't be passing in an empty string
|
||||||
|
|
||||||
|
//TODO: remove the memorySpaceID parameter from this method
|
||||||
|
//after making sure it's not used in earlier implementations
|
||||||
|
//in the mean time check for consistency
|
||||||
|
if(memorySpaceID != null) {
|
||||||
|
assert(context instanceof IMemorySpaceDMContext);
|
||||||
|
assert memorySpaceID.equals(((IMemorySpaceDMContext) context).getMemorySpaceId());
|
||||||
|
} else {
|
||||||
|
if (context instanceof IMemorySpaceDMContext) {
|
||||||
|
assert ((IMemorySpaceDMContext) context).getMemorySpaceId() == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,7 +77,10 @@ public class GdbMemoryBlock extends DsfMemoryBlock implements IMemorySpaceAwareM
|
||||||
|
|
||||||
public MemorySpaceDMContext(String sessionId, String memorySpaceId, IDMContext parent) {
|
public MemorySpaceDMContext(String sessionId, String memorySpaceId, IDMContext parent) {
|
||||||
super(sessionId, new IDMContext[] {parent});
|
super(sessionId, new IDMContext[] {parent});
|
||||||
fMemorySpaceId = memorySpaceId;
|
// A memorySpaceDMContext should not be created if the memorySpaceId is not valid.
|
||||||
|
// However we need the id to calculate the hash, therefore we can not leave it as null
|
||||||
|
assert(memorySpaceId != null);
|
||||||
|
fMemorySpaceId = memorySpaceId == null ? "": memorySpaceId; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -112,150 +121,6 @@ public class GdbMemoryBlock extends DsfMemoryBlock implements IMemorySpaceAwareM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* The real thing. Since the original call is synchronous (from a platform
|
|
||||||
* Job), we use a Query that will patiently wait for the underlying
|
|
||||||
* asynchronous calls to complete before returning.
|
|
||||||
*
|
|
||||||
* @param bigAddress
|
|
||||||
* @param count - The number of addressable units for this block
|
|
||||||
* @return MemoryByte[]
|
|
||||||
* @throws DebugException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected MemoryByte[] fetchMemoryBlock(BigInteger bigAddress, final long count) throws DebugException {
|
|
||||||
|
|
||||||
// For the IAddress interface
|
|
||||||
final Addr64 address = new Addr64(bigAddress);
|
|
||||||
|
|
||||||
// Use a Query to synchronize the downstream calls
|
|
||||||
Query<MemoryByte[]> query = new Query<MemoryByte[]>() {
|
|
||||||
@Override
|
|
||||||
protected void execute(final DataRequestMonitor<MemoryByte[]> drm) {
|
|
||||||
GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval();
|
|
||||||
int addressableSize = 1;
|
|
||||||
try {
|
|
||||||
addressableSize = getAddressableSize();
|
|
||||||
} catch (DebugException e) {}
|
|
||||||
|
|
||||||
// If this block was created with a memory space qualification,
|
|
||||||
// we need to create an enhanced context
|
|
||||||
IMemoryDMContext context = null;
|
|
||||||
if (fMemorySpaceID != null) {
|
|
||||||
IMemorySpaces memoryService = retrieval.getMemorySpaceServiceTracker().getService();
|
|
||||||
if (memoryService != null) {
|
|
||||||
context = new MemorySpaceDMContext(memoryService.getSession().getId(), fMemorySpaceID, getContext());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null));
|
|
||||||
drm.done();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
context = getContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
IMemory memoryService = retrieval.getServiceTracker().getService();
|
|
||||||
if (memoryService != null) {
|
|
||||||
// Go for it
|
|
||||||
memoryService.getMemory(
|
|
||||||
context, address, 0, addressableSize, (int) count,
|
|
||||||
//getContext(), address, 0, addressableSize, (int) length,
|
|
||||||
new DataRequestMonitor<MemoryByte[]>(retrieval.getExecutor(), drm) {
|
|
||||||
@Override
|
|
||||||
protected void handleSuccess() {
|
|
||||||
drm.setData(getData());
|
|
||||||
drm.done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null));
|
|
||||||
drm.done();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval();
|
|
||||||
retrieval.getExecutor().execute(query);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return query.get();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryReadFailed, e));
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryReadFailed, e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Writes an array of bytes to memory.
|
|
||||||
*
|
|
||||||
* @param offset
|
|
||||||
* @param bytes
|
|
||||||
* @throws DebugException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void writeMemoryBlock(final long offset, final byte[] bytes) throws DebugException {
|
|
||||||
|
|
||||||
// For the IAddress interface
|
|
||||||
final Addr64 address = new Addr64(getBigBaseAddress());
|
|
||||||
|
|
||||||
// Use a Query to synchronize the downstream calls
|
|
||||||
Query<MemoryByte[]> query = new Query<MemoryByte[]>() {
|
|
||||||
@Override
|
|
||||||
protected void execute(final DataRequestMonitor<MemoryByte[]> drm) {
|
|
||||||
GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval();
|
|
||||||
int addressableSize = 1;
|
|
||||||
try {
|
|
||||||
addressableSize = getAddressableSize();
|
|
||||||
} catch (DebugException e) {}
|
|
||||||
|
|
||||||
int addressableUnits = bytes.length/addressableSize;
|
|
||||||
|
|
||||||
// If this block was created with a memory space qualification,
|
|
||||||
// we need to create an enhanced context
|
|
||||||
IMemoryDMContext context = null;
|
|
||||||
if (fMemorySpaceID != null) {
|
|
||||||
IMemorySpaces memoryService = retrieval.getMemorySpaceServiceTracker().getService();
|
|
||||||
if (memoryService != null) {
|
|
||||||
context = new MemorySpaceDMContext(memoryService.getSession().getId(), fMemorySpaceID, getContext());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null));
|
|
||||||
drm.done();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
context = getContext();
|
|
||||||
}
|
|
||||||
IMemory memoryService = retrieval.getServiceTracker().getService();
|
|
||||||
if (memoryService != null) {
|
|
||||||
// Go for it
|
|
||||||
memoryService.setMemory(
|
|
||||||
context, address, offset, addressableSize, addressableUnits, bytes,
|
|
||||||
new RequestMonitor(retrieval.getExecutor(), drm));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null));
|
|
||||||
drm.done();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval();
|
|
||||||
retrieval.getExecutor().execute(query);
|
|
||||||
|
|
||||||
try {
|
|
||||||
query.get();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryWriteFailed, e));
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, Messages.Err_MemoryWriteFailed, e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemorySpaceAwareMemoryBlock#getMemorySpaceID()
|
* @see org.eclipse.cdt.debug.internal.core.model.provisional.IMemorySpaceAwareMemoryBlock#getMemorySpaceID()
|
||||||
*/
|
*/
|
||||||
|
@ -283,19 +148,10 @@ public class GdbMemoryBlock extends DsfMemoryBlock implements IMemorySpaceAwareM
|
||||||
@Override
|
@Override
|
||||||
public int getAddressSize() throws DebugException {
|
public int getAddressSize() throws DebugException {
|
||||||
GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval();
|
GdbMemoryBlockRetrieval retrieval = (GdbMemoryBlockRetrieval)getMemoryBlockRetrieval();
|
||||||
IMemoryDMContext context = null;
|
|
||||||
if (fMemorySpaceID != null) {
|
|
||||||
IMemorySpaces memorySpacesService = retrieval.getMemorySpaceServiceTracker().getService();
|
|
||||||
if (memorySpacesService != null) {
|
|
||||||
context = new MemorySpaceDMContext(memorySpacesService.getSession().getId(), fMemorySpaceID, getContext());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
context = getContext();
|
|
||||||
}
|
|
||||||
IGDBMemory memoryService = (IGDBMemory)retrieval.getServiceTracker().getService();
|
IGDBMemory memoryService = (IGDBMemory)retrieval.getServiceTracker().getService();
|
||||||
if (memoryService != null) {
|
if (memoryService != null) {
|
||||||
return memoryService.getAddressSize(context);
|
return memoryService.getAddressSize(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null));
|
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, Messages.Err_MemoryServiceNotAvailable, null));
|
||||||
|
|
|
@ -9,24 +9,30 @@
|
||||||
* Texas Instruments, Freescale Semiconductor - initial API and implementation
|
* Texas Instruments, Freescale Semiconductor - initial API and implementation
|
||||||
* Alvaro Sanchez-Leon (Ericsson AB) - Each memory context needs a different MemoryRetrieval (Bug 250323)
|
* Alvaro Sanchez-Leon (Ericsson AB) - Each memory context needs a different MemoryRetrieval (Bug 250323)
|
||||||
* Alvaro Sanchez-Leon (Ericsson AB) - [Memory] Support 16 bit addressable size (Bug 426730)
|
* Alvaro Sanchez-Leon (Ericsson AB) - [Memory] Support 16 bit addressable size (Bug 426730)
|
||||||
|
* Anders Dahlberg (Ericsson) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
|
* Alvaro Sanchez-Leon (Ericsson AB) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.gdb.internal.memory;
|
package org.eclipse.cdt.dsf.gdb.internal.memory;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
|
||||||
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock;
|
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock;
|
||||||
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval;
|
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlockRetrieval;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
|
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
|
||||||
|
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlock;
|
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlock;
|
||||||
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval;
|
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlockRetrieval;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IMemorySpaces;
|
import org.eclipse.cdt.dsf.debug.service.IMemorySpaces;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IMemorySpaces.IMemorySpaceDMContext;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IMemorySpaces2;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.memory.GdbMemoryBlock.MemorySpaceDMContext;
|
import org.eclipse.cdt.dsf.gdb.internal.memory.GdbMemoryBlock.MemorySpaceDMContext;
|
||||||
import org.eclipse.cdt.dsf.gdb.service.IGDBMemory;
|
import org.eclipse.cdt.dsf.gdb.service.IGDBMemory;
|
||||||
|
@ -105,11 +111,26 @@ public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException {
|
public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException {
|
||||||
// Technically, we don't need to override this method. Letting our base
|
|
||||||
// class create a DsfMemoryBlock would work just fine. But, for the
|
String memorySpaceID = null;
|
||||||
// sake of consistency, lets have this retrieval class always return a
|
|
||||||
// GdbMemoryBlock.
|
// Determine if the expression has memory space information
|
||||||
return getMemoryBlock(expression, context, null);
|
IDMContext dmc = null;
|
||||||
|
if (context instanceof IDMContext) {
|
||||||
|
dmc = (IDMContext) context;
|
||||||
|
} else {
|
||||||
|
if (context instanceof IAdaptable) {
|
||||||
|
dmc = (IDMContext)((IAdaptable)context).getAdapter(IDMContext.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dmc != null) {
|
||||||
|
DecodeResult result = decodeMemorySpaceExpression(dmc, expression);
|
||||||
|
expression = result.getExpression();
|
||||||
|
memorySpaceID = result.getMemorySpaceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getMemoryBlock(expression, context, memorySpaceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -131,6 +152,17 @@ public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Adjust the memory context to use memory spaces when available
|
||||||
|
if (memoryDmc instanceof IMemorySpaceDMContext) {
|
||||||
|
// The memory space ids should match
|
||||||
|
assert(memorySpaceID != null);
|
||||||
|
assert(memorySpaceID.equals(((IMemorySpaceDMContext)memoryDmc).getMemorySpaceId()));
|
||||||
|
} else {
|
||||||
|
if (memorySpaceID != null && memorySpaceID.length() > 0) {
|
||||||
|
memoryDmc = new MemorySpaceDMContext(getSession().getId(), memorySpaceID, memoryDmc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The block start address (supports 64-bit processors)
|
// The block start address (supports 64-bit processors)
|
||||||
BigInteger blockAddress;
|
BigInteger blockAddress;
|
||||||
|
|
||||||
|
@ -177,7 +209,7 @@ public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for block address exceeding maximum allowed address value
|
// check for block address exceeding maximum allowed address value
|
||||||
int addressSize = getAddressSize(memoryDmc, memorySpaceID);
|
int addressSize = getAddressSize(memoryDmc);
|
||||||
BigInteger endAddress = BigInteger.ONE.shiftLeft(addressSize*8).subtract(BigInteger.ONE);
|
BigInteger endAddress = BigInteger.ONE.shiftLeft(addressSize*8).subtract(BigInteger.ONE);
|
||||||
if (endAddress.compareTo(blockAddress) < 0) {
|
if (endAddress.compareTo(blockAddress) < 0) {
|
||||||
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1,
|
throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1,
|
||||||
|
@ -196,7 +228,7 @@ public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements
|
||||||
* same memory block, a trip to the target could result. However,
|
* same memory block, a trip to the target could result. However,
|
||||||
* the memory request cache should save the day.
|
* the memory request cache should save the day.
|
||||||
*/
|
*/
|
||||||
return new GdbMemoryBlock(this, memoryDmc, getModelId(), expression, blockAddress, getAddressableSize(memoryDmc, memorySpaceID), 0, memorySpaceID);
|
return new GdbMemoryBlock(this, memoryDmc, getModelId(), expression, blockAddress, getAddressableSize(memoryDmc), 0, memorySpaceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -283,13 +315,18 @@ public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements
|
||||||
}
|
}
|
||||||
|
|
||||||
// default decoding
|
// default decoding
|
||||||
|
final String memorySpaceID;
|
||||||
|
final String expression;
|
||||||
int index = str.indexOf(':');
|
int index = str.indexOf(':');
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
throw new CoreException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, Messages.Err_InvalidEncodedAddress + ": " + str , null)); //$NON-NLS-1$
|
//Unknown parsing, may not use memory spaces
|
||||||
|
memorySpaceID = null;
|
||||||
|
expression = str;
|
||||||
|
} else {
|
||||||
|
memorySpaceID = str.substring(0, index);
|
||||||
|
expression = (index < str.length()-1) ? str.substring(index+1) : ""; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
final String memorySpaceID = str.substring(0, index);
|
|
||||||
final String expression = (index < str.length()-1) ? str.substring(index+1) : ""; //$NON-NLS-1$
|
|
||||||
return new DecodeResult() {
|
return new DecodeResult() {
|
||||||
@Override
|
@Override
|
||||||
public String getMemorySpaceId() { return memorySpaceID; }
|
public String getMemorySpaceId() { return memorySpaceID; }
|
||||||
|
@ -299,6 +336,67 @@ public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the received expression by
|
||||||
|
* First, decoding the string directly
|
||||||
|
* Second, if the memory space is not found in the expression string, use the Memory service to use some help from gdb
|
||||||
|
*/
|
||||||
|
private DecodeResult decodeMemorySpaceExpression(final IDMContext dmc, final String expression) throws DebugException {
|
||||||
|
DecodeResult decodeResult;
|
||||||
|
try {
|
||||||
|
decodeResult = decodeAddress(expression);
|
||||||
|
} catch (CoreException e1) {
|
||||||
|
throw new DebugException(e1.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decodeResult.getMemorySpaceId() != null) {
|
||||||
|
//memory space found in expression
|
||||||
|
return decodeResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
final IMemorySpaces service = fMemorySpaceServiceTracker.getService();
|
||||||
|
if (service instanceof IMemorySpaces2) {
|
||||||
|
final IMemorySpaces2 memSpaceService = (IMemorySpaces2) service;
|
||||||
|
|
||||||
|
Query<IMemorySpaces.DecodeResult> query = new Query<IMemorySpaces.DecodeResult>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(final DataRequestMonitor<IMemorySpaces.DecodeResult> drm) {
|
||||||
|
memSpaceService.decodeExpression(dmc, expression, drm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getExecutor().execute(query);
|
||||||
|
try {
|
||||||
|
final IMemorySpaces.DecodeResult result = query.get();
|
||||||
|
decodeResult = new DecodeResult() {
|
||||||
|
@Override
|
||||||
|
public String getMemorySpaceId() {
|
||||||
|
return result.getMemorySpaceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExpression() {
|
||||||
|
return result.getExpression();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new DebugException(new Status(IStatus.ERROR,
|
||||||
|
GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
|
||||||
|
"Error evaluating memory space expression (InterruptedException).", e)); //$NON-NLS-1$
|
||||||
|
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
throw new DebugException(new Status(IStatus.ERROR,
|
||||||
|
GdbPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
|
||||||
|
"Error evaluating memory space expression (ExecutionException).", e)); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return decodeResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ServiceTracker<IMemorySpaces, IMemorySpaces> getMemorySpaceServiceTracker() {
|
ServiceTracker<IMemorySpaces, IMemorySpaces> getMemorySpaceServiceTracker() {
|
||||||
return fMemorySpaceServiceTracker;
|
return fMemorySpaceServiceTracker;
|
||||||
}
|
}
|
||||||
|
@ -377,11 +475,19 @@ public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements
|
||||||
if (memorySpaceID.length() == 0) {
|
if (memorySpaceID.length() == 0) {
|
||||||
memorySpaceID = null;
|
memorySpaceID = null;
|
||||||
assert false : "should have either no memory space or a valid (non-empty) ID"; //$NON-NLS-1$
|
assert false : "should have either no memory space or a valid (non-empty) ID"; //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
if (memoryCtx instanceof IMemorySpaceDMContext) {
|
||||||
|
//The context is already a memory space context, make sure the ids are consistent
|
||||||
|
assert(((IMemorySpaceDMContext) memoryCtx).getMemorySpaceId().equals(memorySpaceID));
|
||||||
|
} else {
|
||||||
|
//Use a memory space context if the memory space id is valid
|
||||||
|
memoryCtx = new MemorySpaceDMContext(getSession().getId(), memorySpaceID, memoryCtx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInteger blockAddress = new BigInteger(address);
|
BigInteger blockAddress = new BigInteger(address);
|
||||||
DsfMemoryBlock block = new GdbMemoryBlock(this, memoryCtx, getModelId(), label, blockAddress, getAddressableSize(memoryCtx, memorySpaceID), 0, memorySpaceID);
|
DsfMemoryBlock block = new GdbMemoryBlock(this, memoryCtx, getModelId(), label, blockAddress, getAddressableSize(memoryCtx), 0, memorySpaceID);
|
||||||
blocks.add(block);
|
blocks.add(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,38 +508,22 @@ public class GdbMemoryBlockRetrieval extends DsfMemoryBlockRetrieval implements
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getAddressableSize(IMemoryDMContext aContext, String memorySpaceID) {
|
private int getAddressableSize(IMemoryDMContext context) {
|
||||||
IGDBMemory2 memoryService = (IGDBMemory2) getServiceTracker()
|
IGDBMemory2 memoryService = (IGDBMemory2) getServiceTracker()
|
||||||
.getService();
|
.getService();
|
||||||
|
|
||||||
if (memoryService != null && aContext != null) {
|
if (memoryService != null && context != null) {
|
||||||
IMemoryDMContext context = resolveMemSpaceContext(aContext, memorySpaceID);
|
|
||||||
return memoryService.getAddressableSize(context);
|
return memoryService.getAddressableSize(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getAddressableSize();
|
return super.getAddressableSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getAddressSize(IMemoryDMContext context) {
|
||||||
private int getAddressSize(IMemoryDMContext aContext, String memorySpaceID) {
|
|
||||||
IGDBMemory memoryService = (IGDBMemory)getServiceTracker().getService();
|
IGDBMemory memoryService = (IGDBMemory)getServiceTracker().getService();
|
||||||
if (memoryService != null && aContext != null) {
|
if (memoryService != null && context != null) {
|
||||||
IMemoryDMContext context = resolveMemSpaceContext(aContext, memorySpaceID);
|
|
||||||
return memoryService.getAddressSize(context);
|
return memoryService.getAddressSize(context);
|
||||||
}
|
}
|
||||||
return super.getAddressSize();
|
return super.getAddressSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMemoryDMContext resolveMemSpaceContext(IMemoryDMContext aContext, String aMemorySpaceID) {
|
|
||||||
IMemoryDMContext context = aContext;
|
|
||||||
if (aMemorySpaceID != null && aMemorySpaceID.length() > 0) {
|
|
||||||
IMemorySpaces memorySpacesService = getMemorySpaceServiceTracker().getService();
|
|
||||||
if (memorySpacesService != null) {
|
|
||||||
context = new MemorySpaceDMContext(memorySpacesService.getSession().getId(), aMemorySpaceID, aContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -430,11 +430,6 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Event handlers
|
// Event handlers
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
@DsfServiceEventHandler
|
||||||
public void eventDispatched(IResumedDMEvent e) {
|
public void eventDispatched(IResumedDMEvent e) {
|
||||||
if (e instanceof IContainerResumedDMEvent) {
|
if (e instanceof IContainerResumedDMEvent) {
|
||||||
|
@ -459,10 +454,6 @@ 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
|
@DsfServiceEventHandler
|
||||||
public void eventDispatched(ISuspendedDMEvent e) {
|
public void eventDispatched(ISuspendedDMEvent e) {
|
||||||
if (e instanceof IContainerSuspendedDMEvent) {
|
if (e instanceof IContainerSuspendedDMEvent) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2008, 2013 Monta Vista and others.
|
* Copyright (c) 2008, 2014 Monta Vista and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -14,6 +14,8 @@
|
||||||
* Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
|
* Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
|
||||||
* Axel Mueller - Workaround for GDB bug where -var-info-path-expression gives invalid result (Bug 320277)
|
* Axel Mueller - Workaround for GDB bug where -var-info-path-expression gives invalid result (Bug 320277)
|
||||||
* Anton Gorenkov - DSF-GDB should properly handle variable type change (based on RTTI) (Bug 376901)
|
* Anton Gorenkov - DSF-GDB should properly handle variable type change (based on RTTI) (Bug 376901)
|
||||||
|
* Anders Dahlberg (Ericsson) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
|
* Alvaro Sanchez-Leon (Ericsson) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.mi.service;
|
package org.eclipse.cdt.dsf.mi.service;
|
||||||
|
|
||||||
|
@ -586,7 +588,7 @@ public class MIVariableManager implements ICommandControl {
|
||||||
*/
|
*/
|
||||||
public void setType(String newTypeName) {
|
public void setType(String newTypeName) {
|
||||||
type = newTypeName;
|
type = newTypeName;
|
||||||
gdbType = fGDBTypeParser.parse(newTypeName);
|
gdbType = getGDBTypeParser().parse(newTypeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(String format, String val) { valueMap.put(format, val); }
|
public void setValue(String format, String val) { valueMap.put(format, val); }
|
||||||
|
@ -2542,10 +2544,7 @@ public class MIVariableManager implements ICommandControl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private GDBTypeParser fGDBTypeParser = null;
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
private static final GDBTypeParser fGDBTypeParser = new GDBTypeParser();
|
|
||||||
|
|
||||||
private final DsfSession fSession;
|
private final DsfSession fSession;
|
||||||
|
|
||||||
|
@ -2620,6 +2619,13 @@ public class MIVariableManager implements ICommandControl {
|
||||||
return lruVariableList;
|
return lruVariableList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GDBTypeParser getGDBTypeParser() {
|
||||||
|
if (fGDBTypeParser == null) {
|
||||||
|
fGDBTypeParser = createGDBTypeParser();
|
||||||
|
}
|
||||||
|
return fGDBTypeParser;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method returns a variable object based on the specified
|
* This method returns a variable object based on the specified
|
||||||
* ExpressionDMC, creating it in GDB if it was not created already.
|
* ExpressionDMC, creating it in GDB if it was not created already.
|
||||||
|
@ -3172,4 +3178,12 @@ public class MIVariableManager implements ICommandControl {
|
||||||
protected boolean needFixForGDBBug320277() {
|
protected boolean needFixForGDBBug320277() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.4
|
||||||
|
*/
|
||||||
|
protected GDBTypeParser createGDBTypeParser() {
|
||||||
|
return new GDBTypeParser();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2014 Ericsson AB 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:
|
||||||
|
* Anders Dahlberg (Ericsson) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
|
* Alvaro Sanchez-Leon (Ericsson AB) - Need additional API to extend support for memory spaces (Bug 431627)
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.dsf.debug.service;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This extension allows the decoding of an expression with the help of the external debugger
|
||||||
|
*
|
||||||
|
* @since 2.5
|
||||||
|
*/
|
||||||
|
public interface IMemorySpaces2 extends IMemorySpaces {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the means to use the debugger backend to help with asynchronous
|
||||||
|
* resolution of memory space, expression pair from a single string expression
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void decodeExpression(IDMContext context, String expression, DataRequestMonitor<DecodeResult> rm);
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue