mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-21 21:52:10 +02:00
Bug 489512 - Show local variables in the traditional memory render
Change-Id: I48d633e8f6979fd91e9150856fd77fccffdee299
This commit is contained in:
parent
d608db2e7a
commit
e21fc12f90
16 changed files with 1551 additions and 33 deletions
|
@ -22,7 +22,8 @@ Export-Package: org.eclipse.cdt.debug.core,
|
|||
x-friends:="org.eclipse.cdt.dsf.gdb,
|
||||
org.eclipse.cdt.dsf.gdb.ui,
|
||||
org.eclipse.cdt.dsf,
|
||||
org.eclipse.cdt.dsf.ui",
|
||||
org.eclipse.cdt.dsf.ui,
|
||||
org.eclipse.cdt.debug.ui.memory.traditional",
|
||||
org.eclipse.cdt.debug.internal.core.breakpoints;x-friends:="org.eclipse.cdt.debug.edc,org.eclipse.cdt.dsf.gdb",
|
||||
org.eclipse.cdt.debug.internal.core.disassembly;x-internal:=true,
|
||||
org.eclipse.cdt.debug.internal.core.executables;x-internal:=true,
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.debug.core.model;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.eclipse.debug.core.IRequest;
|
||||
import org.eclipse.debug.core.model.IMemoryBlock;
|
||||
|
||||
/**
|
||||
* An interface that offers the possibility to request information related to addresses for a given memory block
|
||||
* and within a specific context. It also offers the possibility to register listeners, listeners that can receive
|
||||
* notifications of changes/updates to the address information
|
||||
*
|
||||
* @since 8.0
|
||||
*/
|
||||
public interface IMemoryBlockAddressInfoRetrieval {
|
||||
|
||||
|
||||
/**
|
||||
* An indication of the type of change which may render the current memory address information out of date
|
||||
*/
|
||||
enum EventType {
|
||||
STOPPED, RESUMED, VALUE_CHANGED
|
||||
}
|
||||
|
||||
/**
|
||||
* Information item for a memory address or range
|
||||
*/
|
||||
public interface IMemoryBlockAddressInfoItem {
|
||||
/**
|
||||
* @return The unique id for this item
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* @return The type of information
|
||||
*/
|
||||
String getInfoType();
|
||||
|
||||
/**
|
||||
* @return The label or name for this entry
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Update the label or name for this entry
|
||||
*/
|
||||
void setLabel(String label);
|
||||
|
||||
/**
|
||||
* @return The memory address this information is associated to
|
||||
*/
|
||||
BigInteger getAddress();
|
||||
|
||||
/**
|
||||
* @param address Set / Update this item's address
|
||||
*/
|
||||
void setAddress(BigInteger address);
|
||||
|
||||
/**
|
||||
* @return The range of addressable units this information applies to
|
||||
*/
|
||||
BigInteger getRangeInAddressableUnits();
|
||||
|
||||
void setRangeInAddressableUnits(BigInteger length);
|
||||
|
||||
/**
|
||||
* @return A preferred color to mark this entry
|
||||
*/
|
||||
int getRegionRGBColor();
|
||||
|
||||
void setRegionRGBColor(int color);
|
||||
}
|
||||
|
||||
/**
|
||||
* An async request for information items, triggering the callback via the method done().
|
||||
* The method done() is expected to be overridden so when the request is successful this additional API
|
||||
* can be used to retrieve the item information collected.
|
||||
*/
|
||||
public interface IGetMemoryBlockAddressInfoReq extends IRequest {
|
||||
/**
|
||||
* @return The different types of items available
|
||||
*/
|
||||
String[] getAddressInfoItemTypes();
|
||||
|
||||
/**
|
||||
* @return The subset of items of the given type
|
||||
*/
|
||||
IMemoryBlockAddressInfoItem[] getAddressInfoItems(String type);
|
||||
|
||||
/**
|
||||
* @return The full set of items i.e. including all types
|
||||
*/
|
||||
IMemoryBlockAddressInfoItem[] getAllAddressInfoItems();
|
||||
|
||||
/**
|
||||
* Sets the address information items of the given type
|
||||
*/
|
||||
void setAddressInfoItems(String type, IMemoryBlockAddressInfoItem[] items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call-back interface used to receive notification of changes to address information items
|
||||
*/
|
||||
public interface IAddressInfoUpdateListener {
|
||||
/**
|
||||
* This method will be called for each registered listener, when there is a session change that may render
|
||||
* previous memory address information out of date
|
||||
* @param update optional General purpose update object to e.g. determine changed values
|
||||
*/
|
||||
void handleAddressInfoUpdate(EventType type, Object update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an asynchronous request for Memory block address information
|
||||
*
|
||||
* @param context A reference to a session context
|
||||
* @param memoryBlock The memory block to be used in conjunction with the requested Address information
|
||||
* @param request This is the async request instance. Overriding its method "done()" allows to read and
|
||||
* use the information items collected
|
||||
*/
|
||||
void getMemoryBlockAddressInfo(Object context, IMemoryBlock memoryBlock, IGetMemoryBlockAddressInfoReq request);
|
||||
|
||||
/**
|
||||
* Register a listener so it can receive notifications of changes to address information items
|
||||
*
|
||||
* @param listener
|
||||
*/
|
||||
void addAddressInfoUpdateListener(IAddressInfoUpdateListener listener);
|
||||
|
||||
/**
|
||||
* Removes a listener so it no longer receives notifications
|
||||
*
|
||||
* @param The listener to remove. Nothing will happen if that listener is not registered already
|
||||
*/
|
||||
void removeAddressInfoUpdateListener(IAddressInfoUpdateListener listener);
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2015 Ericsson and others.
|
||||
* Copyright (c) 2016 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
|
||||
|
@ -23,6 +23,7 @@ import java.util.Map;
|
|||
import org.eclipse.cdt.debug.core.model.ICBreakpoint;
|
||||
import org.eclipse.cdt.debug.core.model.IConnectHandler;
|
||||
import org.eclipse.cdt.debug.core.model.IDebugNewExecutableHandler;
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval;
|
||||
import org.eclipse.cdt.debug.core.model.IResumeWithoutSignalHandler;
|
||||
import org.eclipse.cdt.debug.core.model.IReverseResumeHandler;
|
||||
import org.eclipse.cdt.debug.core.model.IReverseStepIntoHandler;
|
||||
|
@ -68,6 +69,7 @@ import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbSelectPrevTraceRecordComm
|
|||
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbStartTracingCommand;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbStopTracingCommand;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbUncallCommand;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.ui.memory.GdbMemoryBlockAddressInfoRetrieval;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.GdbViewModelAdapter;
|
||||
import org.eclipse.cdt.dsf.gdb.launching.GdbLaunchDelegate;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
|
@ -214,7 +216,8 @@ public class GdbSessionAdapters {
|
|||
IPinProvider.class,
|
||||
IDebugModelProvider.class,
|
||||
ILaunch.class,
|
||||
ICEditorTextHover.class));
|
||||
ICEditorTextHover.class,
|
||||
IMemoryBlockAddressInfoRetrieval.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -363,6 +366,11 @@ public class GdbSessionAdapters {
|
|||
if (ICEditorTextHover.class.equals(adapterType)) {
|
||||
return (T)new GdbDebugTextHover();
|
||||
}
|
||||
|
||||
if (IMemoryBlockAddressInfoRetrieval.class.equals(adapterType)) {
|
||||
return (T) new GdbMemoryBlockAddressInfoRetrieval(session);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.internal.ui.memory;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval;
|
||||
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
|
||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.model.DsfMemoryBlock;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterChangedDMEvent;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.memory.GdbMemoryAddressInfoVariablesRetrieval;
|
||||
import org.eclipse.cdt.dsf.gdb.memory.IGdbMemoryAddressInfoTypeRetrieval;
|
||||
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
|
||||
import org.eclipse.debug.core.model.IMemoryBlock;
|
||||
|
||||
public class GdbMemoryBlockAddressInfoRetrieval implements IMemoryBlockAddressInfoRetrieval {
|
||||
|
||||
private final DsfSession fSession;
|
||||
private final Set<IAddressInfoUpdateListener> fListeners = new HashSet<>();
|
||||
|
||||
public GdbMemoryBlockAddressInfoRetrieval(DsfSession session) {
|
||||
fSession = session;
|
||||
fSession.getExecutor().execute(new DsfRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fSession.addServiceEventListener(GdbMemoryBlockAddressInfoRetrieval.this, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected IGdbMemoryAddressInfoTypeRetrieval[] resolveMemoryAddressInfoProviders() {
|
||||
return new IGdbMemoryAddressInfoTypeRetrieval[] {new GdbMemoryAddressInfoVariablesRetrieval(fSession)};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getMemoryBlockAddressInfo(Object selection, final IMemoryBlock memBlock,
|
||||
final IGetMemoryBlockAddressInfoReq request) {
|
||||
IDMContext memBlockContext = null;
|
||||
if (memBlock instanceof DsfMemoryBlock) {
|
||||
memBlockContext = ((DsfMemoryBlock) memBlock).getContext();
|
||||
|
||||
if (selection instanceof IDMVMContext) {
|
||||
IDMContext context = ((IDMVMContext) selection).getDMContext();
|
||||
final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(context, IFrameDMContext.class);
|
||||
if (frameCtx != null) {
|
||||
// Resolve container context of selection
|
||||
IContainerDMContext selectedContainerCtx = DMContexts.getAncestorOfType(frameCtx,
|
||||
IContainerDMContext.class);
|
||||
|
||||
// Resolve container context of memory block
|
||||
IContainerDMContext memoryContainerCtx = DMContexts.getAncestorOfType(memBlockContext,
|
||||
IContainerDMContext.class);
|
||||
|
||||
// Continue if the selected container matches the container for the memory context
|
||||
if (memoryContainerCtx != null && memoryContainerCtx.equals(selectedContainerCtx)) {
|
||||
fSession.getExecutor().execute(new DsfRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Resolve the memory address info providers
|
||||
IGdbMemoryAddressInfoTypeRetrieval[] infoTypeProviders = resolveMemoryAddressInfoProviders();
|
||||
if (infoTypeProviders == null || infoTypeProviders.length == 0) {
|
||||
// No providers available
|
||||
request.done();
|
||||
return;
|
||||
}
|
||||
|
||||
final CountingRequestMonitor crm = new CountingRequestMonitor(fSession.getExecutor(),
|
||||
null) {
|
||||
// mark the request done when all available infoTypeProviders have
|
||||
// returned its information
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
request.done();
|
||||
};
|
||||
};
|
||||
|
||||
for (final IGdbMemoryAddressInfoTypeRetrieval infoProvider : infoTypeProviders) {
|
||||
infoProvider.itemsRequest(frameCtx, memBlock,
|
||||
new DataRequestMonitor<IMemoryBlockAddressInfoItem[]>(
|
||||
fSession.getExecutor(), crm) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
if (isSuccess()) {
|
||||
// Load the information from this provider
|
||||
request.setAddressInfoItems(infoProvider.getInfoType(), getData());
|
||||
} else {
|
||||
request.setStatus(getStatus());
|
||||
}
|
||||
crm.done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
crm.setDoneCount(infoTypeProviders.length);
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
request.done();
|
||||
}
|
||||
} else {
|
||||
// The selection context does not match the block memory context,
|
||||
// Simply close the request
|
||||
request.done();
|
||||
}
|
||||
} else {
|
||||
request.done();
|
||||
}
|
||||
} else {
|
||||
request.done();
|
||||
}
|
||||
}
|
||||
|
||||
// The GdbSessionAdapters class will call this method automatically when it cleans up
|
||||
public void dispose() {
|
||||
fListeners.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAddressInfoUpdateListener(IAddressInfoUpdateListener listener) {
|
||||
synchronized(fListeners) {
|
||||
fListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAddressInfoUpdateListener(IAddressInfoUpdateListener listener) {
|
||||
synchronized(fListeners) {
|
||||
fListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@DsfServiceEventHandler
|
||||
public void eventDispatched(IRegisterChangedDMEvent e) {
|
||||
synchronized(fListeners) {
|
||||
for (IAddressInfoUpdateListener listener : fListeners) {
|
||||
listener.handleAddressInfoUpdate(EventType.VALUE_CHANGED, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@DsfServiceEventHandler
|
||||
public void eventDispatched(IExpressionChangedDMEvent e) {
|
||||
synchronized(fListeners) {
|
||||
for (IAddressInfoUpdateListener listener : fListeners) {
|
||||
listener.handleAddressInfoUpdate(EventType.VALUE_CHANGED, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,13 +27,14 @@ Export-Package: org.eclipse.cdt.dsf.gdb,
|
|||
org.eclipse.cdt.tests.dsf.gdb,
|
||||
org.eclipse.cdt.examples.dsf.gdb",
|
||||
org.eclipse.cdt.dsf.gdb.internal.commands;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
|
||||
org.eclipse.cdt.dsf.gdb.internal.memory;x-internal:=true,
|
||||
org.eclipse.cdt.dsf.gdb.internal.memory;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
|
||||
org.eclipse.cdt.dsf.gdb.internal.service.command.commands;x-internal:=true,
|
||||
org.eclipse.cdt.dsf.gdb.internal.service.command.events;x-internal:=true,
|
||||
org.eclipse.cdt.dsf.gdb.internal.service.command.output;x-internal:=true,
|
||||
org.eclipse.cdt.dsf.gdb.internal.service.control;x-internal:=true,
|
||||
org.eclipse.cdt.dsf.gdb.internal.tracepointactions;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.tests.dsf.gdb",
|
||||
org.eclipse.cdt.dsf.gdb.launching,
|
||||
org.eclipse.cdt.dsf.gdb.memory,
|
||||
org.eclipse.cdt.dsf.gdb.service,
|
||||
org.eclipse.cdt.dsf.gdb.service.command,
|
||||
org.eclipse.cdt.dsf.gdb.service.extensions,
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.internal.memory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.IMemoryBlockAddressInfoItem;
|
||||
import org.eclipse.cdt.debug.core.model.provisional.IMemorySpaceAwareMemoryBlock;
|
||||
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.RequestMonitor;
|
||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||
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.IMemorySpaces2;
|
||||
import org.eclipse.cdt.dsf.debug.service.IStack;
|
||||
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMData;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
||||
import org.eclipse.cdt.dsf.gdb.memory.IGdbMemoryAddressInfoTypeRetrieval;
|
||||
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.debug.core.model.IMemoryBlock;
|
||||
|
||||
public class GdbMemoryAddressInfoVariablesRetrieval implements IGdbMemoryAddressInfoTypeRetrieval {
|
||||
|
||||
private final static String VARIABLES_INFO_TYPE = "Variables"; //$NON-NLS-1$
|
||||
private final static int LOCALS_COLOR = 0xB630D1;
|
||||
private final static int POINTER_COLOR = 0xFF0000;
|
||||
private final static String DEREF_CHAR = "*"; //$NON-NLS-1$
|
||||
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
|
||||
private final DsfSession fSession;
|
||||
|
||||
public GdbMemoryAddressInfoVariablesRetrieval(DsfSession session) {
|
||||
fSession = session;
|
||||
}
|
||||
|
||||
private static class MemoryBlockAddressVariableItem extends MemoryBlockAddressInfoItem {
|
||||
public MemoryBlockAddressVariableItem(String name, String value) {
|
||||
super(name, value);
|
||||
}
|
||||
|
||||
public MemoryBlockAddressVariableItem(String name, BigInteger addressValue, BigInteger dataTypeSize,
|
||||
int color) {
|
||||
super(name, addressValue, dataTypeSize, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoType() {
|
||||
return VARIABLES_INFO_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
private final static class ExpressionBin {
|
||||
private final IExpressionDMContext fContext;
|
||||
private IExpressionDMAddress fAddress;
|
||||
private boolean fDereferenced;
|
||||
|
||||
public ExpressionBin(IExpressionDMContext expDmc, boolean dereferenced) {
|
||||
fContext = expDmc;
|
||||
fDereferenced = dereferenced;
|
||||
}
|
||||
|
||||
boolean isDereferenced() {
|
||||
return fDereferenced;
|
||||
}
|
||||
|
||||
boolean isComplete() {
|
||||
if (fContext != null && fAddress != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void itemsRequest(final IDMContext context, final IMemoryBlock memBlock,
|
||||
final DataRequestMonitor<IMemoryBlockAddressInfoItem[]> rm) {
|
||||
if (fSession == null || fSession.getExecutor() == null) {
|
||||
rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Initialization problem, invalid session")); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
|
||||
// resolve handles to the current context
|
||||
final IFrameDMContext frameDmc = DMContexts.getAncestorOfType(context, IFrameDMContext.class);
|
||||
final IStack stackFrameService = resolveService(IStack.class);
|
||||
final IExpressions expressionService = resolveService(IExpressions.class);
|
||||
|
||||
// validate context
|
||||
if (frameDmc == null || expressionService == null || stackFrameService == null) {
|
||||
rm.done(new Status(IStatus.INFO, GdbPlugin.PLUGIN_ID,
|
||||
"Unable to resolve Variables for the currently selected context")); //$NON-NLS-1$
|
||||
return;
|
||||
}
|
||||
|
||||
// Call IStack.getLocals() to get an array of IVariableDMContext objects representing the local
|
||||
// variables in the stack frame represented by frameDmc.
|
||||
final DsfExecutor dsfExecutor = fSession.getExecutor();
|
||||
stackFrameService.getLocals(frameDmc, new DataRequestMonitor<IVariableDMContext[]>(dsfExecutor, rm) {
|
||||
@Override
|
||||
protected void handleSuccess() {
|
||||
// For each IVariableDMContext object returned by IStack.getLocals(), call
|
||||
// MIStackFrameService.getModelData() to get the IVariableDMData object. This requires
|
||||
// a MultiRequestMonitor object.
|
||||
|
||||
// First, get the data model context objects for the local variables.
|
||||
|
||||
IVariableDMContext[] localsDMCs = getData();
|
||||
|
||||
if (localsDMCs == null || localsDMCs.length == 0) {
|
||||
// There are no locals so just complete the request
|
||||
rm.setData(new IMemoryBlockAddressInfoItem[0]);
|
||||
rm.done();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a List in which we store the DM data objects for the local variables. This is
|
||||
// necessary because there is no MultiDataRequestMonitor. :)
|
||||
|
||||
final List<IVariableDMData> localsDMData = new ArrayList<IVariableDMData>();
|
||||
|
||||
// Create the MultiRequestMonitor to handle completion of the set of getModelData() calls.
|
||||
|
||||
final CountingRequestMonitor crm = new CountingRequestMonitor(dsfExecutor, rm) {
|
||||
@Override
|
||||
public void handleSuccess() {
|
||||
// Now that all the calls to getModelData() are complete, we create an
|
||||
// IExpressionDMContext object for each local variable name, saving them all
|
||||
// in an array.
|
||||
ExpressionBin[] expressionBins = new ExpressionBin[localsDMData.size() * 2];
|
||||
int i = 0;
|
||||
for (IVariableDMData localDMData : localsDMData) {
|
||||
|
||||
expressionBins[i++] = createExpression(expressionService, frameDmc, localDMData.getName(),
|
||||
false);
|
||||
expressionBins[i++] = createExpression(expressionService, frameDmc,
|
||||
DEREF_CHAR + localDMData.getName(), true);
|
||||
}
|
||||
|
||||
// Lastly, we fill the update from the array of view model context objects
|
||||
// that reference the ExpressionDMC objects for the local variables. This is
|
||||
// the last code to run for a given call to updateElementsInSessionThread().
|
||||
// We can now leave anonymous-inner-class hell.
|
||||
resolveItems(expressionService, expressionBins, frameDmc, memBlock, rm);
|
||||
}
|
||||
};
|
||||
|
||||
int countRM = 0;
|
||||
// Perform a set of getModelData() calls, one for each local variable's data model
|
||||
// context object. In the handleCompleted() method of the DataRequestMonitor, add the
|
||||
// IVariableDMData object to the localsDMData List for later processing (see above).
|
||||
for (IVariableDMContext localDMC : localsDMCs) {
|
||||
stackFrameService.getVariableData(localDMC,
|
||||
new DataRequestMonitor<IVariableDMData>(dsfExecutor, crm) {
|
||||
@Override
|
||||
public void handleSuccess() {
|
||||
localsDMData.add(getData());
|
||||
crm.done();
|
||||
}
|
||||
});
|
||||
|
||||
countRM++;
|
||||
}
|
||||
crm.setDoneCount(countRM);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInfoType() {
|
||||
return VARIABLES_INFO_TYPE;
|
||||
}
|
||||
|
||||
private void resolveItems(final IExpressions expressionService, final ExpressionBin[] expressionsBins,
|
||||
final IFrameDMContext frameDmc, final IMemoryBlock memBlock,
|
||||
final DataRequestMonitor<IMemoryBlockAddressInfoItem[]> rm) {
|
||||
final DsfExecutor executor = expressionService.getExecutor();
|
||||
|
||||
resolveAddressData(expressionService, expressionsBins, new RequestMonitor(executor, rm) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
// resolve the default memory space id for the current context
|
||||
IMemorySpaces2 memSpaceService = resolveService(IMemorySpaces2.class);
|
||||
if (memSpaceService != null) {
|
||||
memSpaceService.getDefaultMemorySpace(frameDmc, new DataRequestMonitor<String>(executor, rm) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
String defaultMemSpaceId = getData();
|
||||
rm.setData(createAddressInfoItems(expressionsBins, memBlock, defaultMemSpaceId));
|
||||
rm.done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
rm.setData(createAddressInfoItems(expressionsBins, memBlock, EMPTY_STRING));
|
||||
rm.done();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <V> V resolveService(Class<V> type) {
|
||||
V service = null;
|
||||
if (fSession != null) {
|
||||
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getDefault().getBundle().getBundleContext(),
|
||||
fSession.getId());
|
||||
service = tracker.getService(type);
|
||||
tracker.dispose();
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
private ExpressionBin createExpression(IExpressions expressionService, final IDMContext dmc,
|
||||
final String expression, boolean dereferenced) {
|
||||
IExpressionDMContext exprDMC = expressionService.createExpression(dmc, expression);
|
||||
|
||||
// if (fCastToTypeSupport != null) {
|
||||
// exprDMC = fCastToTypeSupport.replaceWithCastedExpression(exprDMC);
|
||||
// }
|
||||
return new ExpressionBin(exprDMC, dereferenced);
|
||||
}
|
||||
|
||||
private void resolveAddressData(IExpressions expressionService, ExpressionBin[] expressionsBins,
|
||||
final RequestMonitor rm) {
|
||||
DsfExecutor executor = expressionService.getExecutor();
|
||||
final CountingRequestMonitor crm = new CountingRequestMonitor(executor, rm);
|
||||
for (final ExpressionBin expBin : expressionsBins) {
|
||||
expressionService.getExpressionAddressData(expBin.fContext,
|
||||
new DataRequestMonitor<IExpressionDMAddress>(executor, crm) {
|
||||
@Override
|
||||
protected void handleCompleted() {
|
||||
if (isSuccess()) {
|
||||
expBin.fAddress = getData();
|
||||
}
|
||||
crm.done();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
crm.setDoneCount(expressionsBins.length);
|
||||
}
|
||||
|
||||
private IMemoryBlockAddressInfoItem[] createAddressInfoItems(ExpressionBin[] contentsBins, IMemoryBlock memBlock,
|
||||
String ctxDefaultMemSpaceId) {
|
||||
|
||||
int length = contentsBins.length;
|
||||
final List<IMemoryBlockAddressInfoItem> infoItems = new ArrayList<IMemoryBlockAddressInfoItem>();
|
||||
|
||||
// Resolve the memory space id of the memory block
|
||||
String memBlockMemSpaceId = EMPTY_STRING;
|
||||
if (memBlock instanceof IMemorySpaceAwareMemoryBlock) {
|
||||
String tMemBlockMemSpace = ((IMemorySpaceAwareMemoryBlock) memBlock).getMemorySpaceID();
|
||||
memBlockMemSpaceId = tMemBlockMemSpace == null ? EMPTY_STRING : tMemBlockMemSpace;
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
ExpressionBin expBin = contentsBins[i];
|
||||
if (!expBin.isComplete()) {
|
||||
// invalid item
|
||||
continue;
|
||||
}
|
||||
|
||||
IExpressionDMAddress dmAddress = expBin.fAddress;
|
||||
BigInteger addressValue = dmAddress.getAddress().getValue();
|
||||
// Skip addresses of zero, likely not yet initialized
|
||||
if (!addressValue.equals(BigInteger.ZERO)) {
|
||||
String name = expBin.fContext.getExpression();
|
||||
BigInteger exprSize = BigInteger.valueOf(dmAddress.getSize());
|
||||
|
||||
final int color;
|
||||
if (expBin.isDereferenced()) {
|
||||
color = POINTER_COLOR;
|
||||
} else {
|
||||
color = LOCALS_COLOR;
|
||||
}
|
||||
|
||||
// Resolve the memory space of the expression
|
||||
String exprMemSpaceId = EMPTY_STRING;
|
||||
String exprMemSpace = dmAddress.getMemorySpaceID();
|
||||
exprMemSpaceId = exprMemSpace != null ? exprMemSpace : EMPTY_STRING;
|
||||
|
||||
// if the memory space of the block is valid and the memory space id of the expression is empty,
|
||||
// use the context default memory space id for the expression.
|
||||
if (memBlockMemSpaceId.length() > 0 && exprMemSpaceId.length() == 0) {
|
||||
exprMemSpaceId = ctxDefaultMemSpaceId;
|
||||
}
|
||||
|
||||
// If the expression's address is in the same memory space as the memory block create a new item
|
||||
if (exprMemSpaceId.equals(memBlockMemSpaceId)) {
|
||||
infoItems.add(new MemoryBlockAddressVariableItem(name, addressValue, exprSize, color));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return infoItems.toArray(new IMemoryBlockAddressInfoItem[infoItems.size()]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 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
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.dsf.gdb.internal.memory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.IMemoryBlockAddressInfoItem;
|
||||
|
||||
/**
|
||||
* A base partial implementation of a a memory block address information item
|
||||
*
|
||||
*/
|
||||
public abstract class MemoryBlockAddressInfoItem implements IMemoryBlockAddressInfoItem {
|
||||
private final String fName;
|
||||
private String fLabel;
|
||||
private BigInteger fAddress;
|
||||
private BigInteger fLength = BigInteger.ONE;
|
||||
private int fColor = 0;
|
||||
|
||||
private MemoryBlockAddressInfoItem(String id, BigInteger address) {
|
||||
fName = id;
|
||||
fLabel = id;
|
||||
fAddress = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param address String representation of a memory address in hex format
|
||||
*/
|
||||
public MemoryBlockAddressInfoItem(String id, String address) {
|
||||
this(id, convertValue(address));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param color int value where the lowest three octets represent the corresponding RGB value
|
||||
*/
|
||||
public MemoryBlockAddressInfoItem(String id, BigInteger address, BigInteger length, int color) {
|
||||
this(id, address);
|
||||
fLength = length;
|
||||
fColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return fName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getRangeInAddressableUnits() {
|
||||
return fLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRegionRGBColor() {
|
||||
return fColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return fLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLabel(String label) {
|
||||
fLabel = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getAddress() {
|
||||
return fAddress;
|
||||
}
|
||||
|
||||
private static BigInteger convertValue(String inValue) {
|
||||
// Make sure we provide a valid hex representation or zero
|
||||
int radix = 16;
|
||||
BigInteger hexValue = null;
|
||||
String value = inValue.replaceAll("0x", ""); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
try {
|
||||
hexValue = new BigInteger(value, radix);
|
||||
} catch (NumberFormatException e) {
|
||||
hexValue = BigInteger.ZERO;
|
||||
}
|
||||
|
||||
return hexValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRangeInAddressableUnits(BigInteger length) {
|
||||
fLength = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegionRGBColor(int color) {
|
||||
fColor = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddress(BigInteger address) {
|
||||
fAddress = address;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.memory;
|
||||
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.IMemoryBlockAddressInfoItem;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||
import org.eclipse.debug.core.model.IMemoryBlock;
|
||||
|
||||
/**
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface IGdbMemoryAddressInfoTypeRetrieval {
|
||||
/**
|
||||
* @return the String representing the type of information items being provided
|
||||
*/
|
||||
String getInfoType();
|
||||
|
||||
/**
|
||||
* The implementation provides the items of an associated type which could be pointing to a memory address
|
||||
*/
|
||||
void itemsRequest(IDMContext selectionContext, IMemoryBlock memoryBlock,
|
||||
DataRequestMonitor<IMemoryBlockAddressInfoItem[]> rm);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007, 2014 Wind River Systems and others.
|
||||
* Copyright (c) 2007, 2016 Wind River Systems 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
|
||||
|
@ -26,9 +26,9 @@ import org.eclipse.cdt.dsf.concurrent.Query;
|
|||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.cdt.dsf.debug.internal.provisional.model.IMemoryBlockUpdatePolicyProvider;
|
||||
import org.eclipse.cdt.dsf.debug.service.IMemory;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRunControl;
|
||||
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.IRunControl;
|
||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
|
||||
import org.eclipse.cdt.dsf.internal.DsfPlugin;
|
||||
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
|
||||
|
@ -782,9 +782,9 @@ public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtens
|
|||
/**
|
||||
* Get the context specified at construction.
|
||||
*
|
||||
* @since 2.1
|
||||
* @since 2.7
|
||||
*/
|
||||
protected IMemoryDMContext getContext() {
|
||||
public IMemoryDMContext getContext() {
|
||||
return fContext;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -874,24 +874,19 @@ public abstract class AbstractPane extends Canvas
|
|||
{
|
||||
super.setFont(font);
|
||||
fCharacterWidth = -1;
|
||||
fCellHeight = -1;
|
||||
fTextHeight = -1;
|
||||
}
|
||||
|
||||
private int fCellHeight = -1; // called often, cache
|
||||
protected int getCellHeight() {
|
||||
// If additional information is to be inserted between lines
|
||||
// double the height
|
||||
int multiplier = fRendering.hasVisibleRangeInfo() ? 2 : 1;
|
||||
int cellHeight = getCellTextHeight() * multiplier + (fRendering.getCellPadding() * 2);
|
||||
|
||||
protected int getCellHeight()
|
||||
{
|
||||
if(fCellHeight == -1)
|
||||
{
|
||||
fCellHeight = getCellTextHeight()
|
||||
+ (fRendering.getCellPadding() * 2);
|
||||
}
|
||||
|
||||
return fCellHeight;
|
||||
return cellHeight;
|
||||
}
|
||||
|
||||
private int fCharacterWidth = -1; // called often, cache
|
||||
private int fCharacterWidth = -1; // called often, cache
|
||||
|
||||
protected int getCellCharacterWidth()
|
||||
{
|
||||
|
|
|
@ -15,7 +15,6 @@ import java.math.BigInteger;
|
|||
|
||||
import org.eclipse.debug.core.DebugException;
|
||||
import org.eclipse.swt.events.PaintEvent;
|
||||
import org.eclipse.swt.graphics.FontMetrics;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
|
||||
|
@ -211,15 +210,13 @@ public class AddressPane extends AbstractPane
|
|||
|
||||
GC gc = pe.gc;
|
||||
|
||||
FontMetrics fontMetrics = gc.getFontMetrics();
|
||||
int textHeight = fontMetrics.getHeight();
|
||||
int cellHeight = textHeight + (fRendering.getCellPadding() * 2);
|
||||
int cellHeight = getCellHeight();
|
||||
|
||||
try
|
||||
{
|
||||
BigInteger start = fRendering.getViewportStartAddress();
|
||||
|
||||
for(int i = 0; i < this.getBounds().height / cellHeight; i++)
|
||||
for(int i = 0; i < fRendering.getRowCount(); i++)
|
||||
{
|
||||
gc.setForeground(fRendering.getTraditionalRendering().getColorText());
|
||||
BigInteger lineAddress = start.add(BigInteger.valueOf(i
|
||||
|
|
|
@ -13,13 +13,20 @@
|
|||
package org.eclipse.cdt.debug.ui.memory.traditional;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.IMemoryBlockAddressInfoItem;
|
||||
import org.eclipse.debug.core.DebugException;
|
||||
import org.eclipse.debug.core.model.MemoryByte;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.MouseTrackAdapter;
|
||||
import org.eclipse.swt.events.PaintEvent;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
|
@ -33,6 +40,8 @@ import org.eclipse.swt.widgets.Shell;
|
|||
public class DataPane extends AbstractPane
|
||||
{
|
||||
private Shell fToolTipShell;
|
||||
private final static String UNICODE_NORTH_WEST_ARROW = "\u2196";
|
||||
|
||||
public DataPane(Rendering parent)
|
||||
{
|
||||
super(parent);
|
||||
|
@ -144,8 +153,8 @@ public class DataPane extends AbstractPane
|
|||
* @return The width length in pixels needed to draw the characters of an addressable unit
|
||||
*/
|
||||
private int getAddressableWidth() {
|
||||
// derive the number of characters per addressable size e.g. 2 * NumOfOctets
|
||||
int charsPerOctet = 2;
|
||||
// derive the number of characters per addressable size e.g. 2 * NumOfOctets for hex representation
|
||||
int charsPerOctet = fRendering.getRadixCharacterCount(fRendering.getRadix(), 1);
|
||||
int addressCharacterCount = fRendering.getAddressableSize() * charsPerOctet;
|
||||
// derive width by multiplying by the size of a character
|
||||
return addressCharacterCount * getCellCharacterWidth();
|
||||
|
@ -221,6 +230,30 @@ public class DataPane extends AbstractPane
|
|||
return cellBaseAddress.add(BigInteger.valueOf(addressableOffset));
|
||||
}
|
||||
|
||||
private Point getAddressLocation(BigInteger address) {
|
||||
// Resolve the location of the cell
|
||||
Point cellLocation = getCellLocation(address);
|
||||
|
||||
// Resolve the first address in the cell
|
||||
BigInteger baseAddress;
|
||||
try {
|
||||
baseAddress = getCellAddressAt(cellLocation.x, cellLocation.y);
|
||||
} catch (DebugException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (baseAddress == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int addressSpan = address.subtract(baseAddress).intValue();
|
||||
// Resolve the horizontal distance from base address to given address in octets
|
||||
int charsWidth = fRendering.getRadixCharacterCount(fRendering.getRadix(), addressSpan) * getCellCharacterWidth();
|
||||
|
||||
return new Point(cellLocation.x + charsWidth, cellLocation.y);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Point getCellLocation(BigInteger cellAddress)
|
||||
{
|
||||
|
@ -254,6 +287,51 @@ public class DataPane extends AbstractPane
|
|||
}
|
||||
}
|
||||
|
||||
private Point getRowFirstCellLocation(BigInteger cellAddress) {
|
||||
try {
|
||||
BigInteger address = fRendering.getViewportStartAddress();
|
||||
|
||||
// cell offset from base address in octets
|
||||
int cellOffset = cellAddress.subtract(address).intValue();
|
||||
cellOffset *= fRendering.getAddressableSize();
|
||||
|
||||
int row = cellOffset / (fRendering.getColumnCount() * fRendering.getBytesPerColumn());
|
||||
|
||||
// column zero plus cell padding
|
||||
int x = fRendering.getCellPadding();
|
||||
int y = row * getCellHeight() + fRendering.getCellPadding();
|
||||
|
||||
return new Point(x, y);
|
||||
} catch (Exception e) {
|
||||
fRendering.logError(
|
||||
TraditionalRenderingMessages.getString("TraditionalRendering.FAILURE_DETERMINE_CELL_LOCATION"), e); //$NON-NLS-1$
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Point getRowLastCellLocation(BigInteger cellAddress) {
|
||||
try {
|
||||
BigInteger address = fRendering.getViewportStartAddress();
|
||||
|
||||
// cell offset from base address in octets
|
||||
int cellOffset = cellAddress.subtract(address).intValue();
|
||||
cellOffset *= fRendering.getAddressableSize();
|
||||
|
||||
int row = cellOffset / (fRendering.getColumnCount() * fRendering.getBytesPerColumn());
|
||||
|
||||
int col = fRendering.getColumnCount() - 1;
|
||||
|
||||
int x = col * getCellWidth() + fRendering.getCellPadding();
|
||||
int y = row * getCellHeight() + fRendering.getCellPadding();
|
||||
|
||||
return new Point(x, y);
|
||||
} catch (Exception e) {
|
||||
fRendering.logError(
|
||||
TraditionalRenderingMessages.getString("TraditionalRendering.FAILURE_DETERMINE_CELL_LOCATION"), e); //$NON-NLS-1$
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void positionCaret(int x, int y)
|
||||
{
|
||||
|
@ -327,7 +405,7 @@ public class DataPane extends AbstractPane
|
|||
{
|
||||
BigInteger startAddress = fRendering.getViewportStartAddress();
|
||||
|
||||
for(int i = 0; i < this.getBounds().height / cellHeight; i++)
|
||||
for(int i = 0; i < fRendering.getRowCount(); i++)
|
||||
{
|
||||
for(int col = 0; col < columns; col++)
|
||||
{
|
||||
|
@ -405,6 +483,8 @@ public class DataPane extends AbstractPane
|
|||
cellHeight);
|
||||
}
|
||||
}
|
||||
|
||||
markAddressesWithAdditionalInfo(gc);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -414,6 +494,219 @@ public class DataPane extends AbstractPane
|
|||
|
||||
}
|
||||
|
||||
private void markAddressesWithAdditionalInfo(GC gc) {
|
||||
if (fRendering.isDisposed() || !fRendering.isVisible() || isDisposed()) {
|
||||
return;
|
||||
}
|
||||
final Map<BigInteger, List<IMemoryBlockAddressInfoItem>> addressToInfoItems = fRendering
|
||||
.getVisibleValueToAddressInfoItems();
|
||||
|
||||
// Check if there are information items available
|
||||
if (addressToInfoItems.size() < 1) {
|
||||
return;
|
||||
}
|
||||
// Prepare to enclose addresses with additional info in a rectangle
|
||||
int addressableWidth = getAddressableWidth();
|
||||
assert addressableWidth > 0;
|
||||
|
||||
// Initialize the dimensions for the rectangle
|
||||
int width = 1;
|
||||
int leftMargin = 1;
|
||||
int rightMargin = leftMargin + 1;
|
||||
int lowerMargin = 1;
|
||||
int lineWidth = 2;
|
||||
int height = getCellTextHeight() - fRendering.getCellPadding() + lowerMargin;
|
||||
|
||||
// Save current GC settings
|
||||
Color origColor = gc.getForeground();
|
||||
int origLineWidth = gc.getLineWidth();
|
||||
|
||||
gc.setForeground(fRendering.getTraditionalRendering().getColorChanged());
|
||||
|
||||
// Set the thickness of the lines being drawn, i.e. thicker than the default
|
||||
gc.setLineWidth(lineWidth);
|
||||
|
||||
// Loop for each address from lowest to highest value
|
||||
BigInteger[] sortedAddresses = orderItemsAscending(addressToInfoItems.keySet());
|
||||
// Define rectangle margin space
|
||||
for (BigInteger startAddress : sortedAddresses) {
|
||||
// Resolve rectangle starting point and start / end row references
|
||||
Point location = getAddressLocation(startAddress);
|
||||
Point firstCellInRow = getRowFirstCellLocation(startAddress);
|
||||
Point lastCellInRow = getRowLastCellLocation(startAddress);
|
||||
|
||||
// Mark each item even if they point to the same start address,
|
||||
// so the end address is visible on each of them
|
||||
List<IMemoryBlockAddressInfoItem> sameStartAddressitems = addressToInfoItems.get(startAddress);
|
||||
// Sort items starting in the same address to draw longest first, this will give more visibility to the embedded markings
|
||||
IMemoryBlockAddressInfoItem[] sameStartOrderedItems = orderItemsByLengthDescending(sameStartAddressitems);
|
||||
for (IMemoryBlockAddressInfoItem item : sameStartOrderedItems) {
|
||||
BigInteger addressUnits = item.getRangeInAddressableUnits();
|
||||
|
||||
// Resolve the color for the rectangle
|
||||
Color rangeColor = resolveColor(item.getRegionRGBColor());
|
||||
if (rangeColor != null) {
|
||||
gc.setForeground(rangeColor);
|
||||
}
|
||||
|
||||
// The start and end address are part of the length so we need to decrement / adjust by one
|
||||
BigInteger endAddress = startAddress.add(addressUnits.subtract(BigInteger.ONE));
|
||||
|
||||
// End location to the start of next address may change to a different row
|
||||
// So it's best to add the addressable width to the beginning of the last address
|
||||
Point endLocation = getAddressLocation(endAddress);
|
||||
endLocation.x = endLocation.x + addressableWidth;
|
||||
|
||||
// Resolve the rows index as the selection may span multiple rows
|
||||
int rowsIndex = (endLocation.y - location.y) / getCellHeight();
|
||||
|
||||
for (int i = 0; i <= rowsIndex; i++) {
|
||||
Point rowLocation = new Point(firstCellInRow.x, firstCellInRow.y + i * getCellHeight());
|
||||
if (!isRowVisible(rowLocation.y)) {
|
||||
// No need to draw the portion of lines outside the visible area
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
// Enclosing range in first row
|
||||
if (endLocation.y == location.y) {
|
||||
// End and beginning locations are in the same row
|
||||
width = endLocation.x - location.x + rightMargin;
|
||||
gc.drawRectangle(location.x - leftMargin, location.y, width, height);
|
||||
} else {
|
||||
// The end cell is in a different row,
|
||||
// mark from the location to the end of this row
|
||||
width = lastCellInRow.x + addressableWidth * fRendering.getAddressesPerColumn() - location.x + rightMargin;
|
||||
// open ended first row
|
||||
location.x -= leftMargin;
|
||||
drawRectangleOpenEnd(location, width, height, gc);
|
||||
}
|
||||
} else if (i > 0 && i < rowsIndex) {
|
||||
// The marking started before this row and finishes after this row
|
||||
// we need to mark the whole row with opened ends i.e. two bordering lines top / bottom
|
||||
width = lastCellInRow.x + addressableWidth * fRendering.getAddressesPerColumn() - firstCellInRow.x + rightMargin;
|
||||
// parallel lines row
|
||||
assert width > 0;
|
||||
rowLocation.x -= leftMargin;
|
||||
drawParallelLines(rowLocation, width, height, gc);
|
||||
} else if (i == rowsIndex) {
|
||||
// The last row to highlight
|
||||
width = endLocation.x - firstCellInRow.x + rightMargin;
|
||||
// Draw a colored rectangle around the addressable units
|
||||
rowLocation.x -= leftMargin;
|
||||
drawRectangleOpenStart(rowLocation, width, height, gc);
|
||||
}
|
||||
}
|
||||
|
||||
// Display the associated textual information
|
||||
String info = fRendering.buildAddressInfoString(startAddress, ",", false);
|
||||
if (info.length() > 0) {
|
||||
// Add one character e.g. up arrow, to indicate the start of the data i.e. upper or lower row
|
||||
gc.drawText(UNICODE_NORTH_WEST_ARROW + info, location.x, location.y + getCellTextHeight());
|
||||
}
|
||||
|
||||
if (rangeColor != null) {
|
||||
rangeColor.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Restore the original color
|
||||
gc.setForeground(origColor);
|
||||
gc.setLineWidth(origLineWidth);
|
||||
}
|
||||
|
||||
private IMemoryBlockAddressInfoItem[] orderItemsByLengthDescending(
|
||||
List<IMemoryBlockAddressInfoItem> sameStartAddressitems) {
|
||||
|
||||
if (sameStartAddressitems.isEmpty() || sameStartAddressitems.size() == 1) {
|
||||
// One item, nothing to sort
|
||||
return sameStartAddressitems
|
||||
.toArray(new IMemoryBlockAddressInfoItem[sameStartAddressitems.size()]);
|
||||
}
|
||||
|
||||
// Perform a bubble sort
|
||||
boolean swapped = true;
|
||||
IMemoryBlockAddressInfoItem temp;
|
||||
|
||||
for (int i = 0; i < sameStartAddressitems.size() - 1; i++) {
|
||||
swapped = false;
|
||||
for (int j = 0; j < sameStartAddressitems.size() - i - 1; j++) {
|
||||
// If current index item is smaller then swap to get reverse sorting
|
||||
if (sameStartAddressitems.get(j).getRangeInAddressableUnits()
|
||||
.compareTo(sameStartAddressitems.get(j + 1).getRangeInAddressableUnits()) < 0) {
|
||||
temp = sameStartAddressitems.get(j);
|
||||
sameStartAddressitems.set(j, sameStartAddressitems.get(j + 1));
|
||||
sameStartAddressitems.set(j + 1, temp);
|
||||
swapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (swapped == false) {
|
||||
// No swaps were needed, we are done!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sameStartAddressitems.toArray(new IMemoryBlockAddressInfoItem[sameStartAddressitems.size()]);
|
||||
}
|
||||
|
||||
private BigInteger[] orderItemsAscending(Set<BigInteger> keySet) {
|
||||
List<BigInteger> collection = new ArrayList<>(keySet);
|
||||
Collections.sort(collection);
|
||||
return collection.toArray(new BigInteger[collection.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from int to RGB octets to then create the corresponding Color
|
||||
*/
|
||||
private Color resolveColor(int intColor) {
|
||||
return new Color(getDisplay(), intColor >> 16, (intColor >> 8) & 0xff, intColor & 0xff);
|
||||
}
|
||||
|
||||
private boolean isRowVisible(int y) {
|
||||
int firstVisibleRow = getAddressLocation(fRendering.getViewportStartAddress()).y;
|
||||
int lastVisibleRow = getAddressLocation(fRendering.getViewportEndAddress()).y;
|
||||
if (y >= firstVisibleRow && y <= lastVisibleRow) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void drawRectangleOpenStart(Point location, int width, int height, GC gc) {
|
||||
gc.drawRectangle(location.x, location.y, width, height);
|
||||
// clear start border
|
||||
eraseVerticalLine(location, height, gc);
|
||||
}
|
||||
|
||||
private void drawRectangleOpenEnd(Point location, int width, int height, GC gc) {
|
||||
gc.drawRectangle(location.x, location.y, width, height);
|
||||
// clear end border
|
||||
Point erasep = new Point(location.x + width, location.y);
|
||||
eraseVerticalLine(erasep, height, gc);
|
||||
}
|
||||
|
||||
private void eraseVerticalLine(Point erasep, int height, GC gc) {
|
||||
Color currentColor = gc.getForeground();
|
||||
gc.setForeground(fRendering.getTraditionalRendering().getColorBackground());
|
||||
gc.drawLine(erasep.x, erasep.y, erasep.x, erasep.y + height);
|
||||
gc.setForeground(currentColor);
|
||||
}
|
||||
|
||||
private void drawParallelLines(Point location, int width, int height, GC gc) {
|
||||
// NOTE: Writing parallel lines would be preferred, however this did not work in my environment
|
||||
// gc.drawLine(location.x, location.y , location.x + width, location.y);
|
||||
// gc.drawLine(location.x, location.y + height, location.x + width, location.y + height);
|
||||
|
||||
// So we use the work around of writing a rectangle and erase start / end borders
|
||||
gc.drawRectangle(location.x, location.y, width, height);
|
||||
// clear start border
|
||||
eraseVerticalLine(location, height, gc);
|
||||
// clear end border
|
||||
Point erasep = new Point(location.x + width, location.y);
|
||||
eraseVerticalLine(erasep, height, gc);
|
||||
}
|
||||
|
||||
// Allow subclasses to override this method to do their own coloring
|
||||
protected void applyCustomColor(GC gc, TraditionalMemoryByte bytes[], int col)
|
||||
{
|
||||
|
@ -532,6 +825,14 @@ public class DataPane extends AbstractPane
|
|||
// Show the current hovering address as the first line in the tooltip
|
||||
StringBuilder sb = new StringBuilder("0x").append(subAddress.toString(16));
|
||||
|
||||
// Add additional address information, if available
|
||||
if (fRendering.hasAddressInfo(subAddress)) {
|
||||
String info = fRendering.buildAddressInfoString(subAddress, "\n", true);
|
||||
if (info.length() > 0) {
|
||||
sb.append("\n").append(info);
|
||||
}
|
||||
}
|
||||
|
||||
fLabelContent.setText(sb.toString());
|
||||
|
||||
// Setting location of the tool tip
|
||||
|
|
|
@ -17,12 +17,15 @@ package org.eclipse.cdt.debug.ui.memory.traditional;
|
|||
import java.math.BigInteger;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.IMemoryBlockAddressInfoItem;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.debug.core.DebugEvent;
|
||||
|
@ -156,6 +159,14 @@ public class Rendering extends Composite implements IDebugEventSetListener
|
|||
public final static int UPDATE_MANUAL = 3;
|
||||
public int fUpdateMode = UPDATE_ALWAYS;
|
||||
|
||||
/**
|
||||
* Maintains the subset of items visible in the current view address range.
|
||||
* This information is refreshed when the associated Panes are about to be redrawn
|
||||
* @since 1.4
|
||||
*/
|
||||
protected final Map<BigInteger, List<IMemoryBlockAddressInfoItem>> fMapStartAddrToInfoItems = Collections
|
||||
.synchronizedMap(new HashMap<BigInteger, List<IMemoryBlockAddressInfoItem>>());
|
||||
|
||||
public Rendering(Composite parent, TraditionalRendering renderingParent)
|
||||
{
|
||||
super(parent, SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.H_SCROLL
|
||||
|
@ -1184,6 +1195,8 @@ public class Rendering extends Composite implements IDebugEventSetListener
|
|||
fViewportCache.dispose();
|
||||
fViewportCache = null;
|
||||
}
|
||||
|
||||
fMapStartAddrToInfoItems.clear();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -1625,7 +1638,10 @@ public class Rendering extends Composite implements IDebugEventSetListener
|
|||
((AbstractPane) panes[i]).getRowCount());
|
||||
}
|
||||
|
||||
return rowCount;
|
||||
// Add an extra row of information as we can present part of the information on
|
||||
// the remaining space of the canvas
|
||||
int extra = 1;
|
||||
return rowCount + extra;
|
||||
}
|
||||
|
||||
public int getBytesPerColumn()
|
||||
|
@ -2293,4 +2309,38 @@ public class Rendering extends Composite implements IDebugEventSetListener
|
|||
final List<AbstractPane> panes = Arrays.asList(getRenderingPanes());
|
||||
return panes.get((panes.indexOf(currentPane) + offset) % panes.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if additional address information is available to display in the current visible range
|
||||
*/
|
||||
boolean hasVisibleRangeInfo() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the given address has additional information to display e.g. variables, registers, etc.
|
||||
*/
|
||||
boolean hasAddressInfo(BigInteger address) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The items that would be visible in the current viewable area if the rows were to use a single
|
||||
* height
|
||||
*/
|
||||
Map<BigInteger, List<IMemoryBlockAddressInfoItem>> getVisibleValueToAddressInfoItems() {
|
||||
return fMapStartAddrToInfoItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a string with the information relevant to a given address, the separator helps to format it
|
||||
* e.g. Separated items by comma, new line, etc.
|
||||
*
|
||||
* @param addTypeHeaders
|
||||
* Indicates if the string shall include a data type name before each list of items of the same
|
||||
* type e.g. Variables, Regitsters, etc.
|
||||
*/
|
||||
String buildAddressInfoString(BigInteger address, String separator, boolean addTypeHeaders) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,395 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 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:
|
||||
* Ericsson - initial API and implementation
|
||||
* *******************************************************************************/
|
||||
package org.eclipse.cdt.debug.ui.memory.traditional;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval;
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.EventType;
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.IAddressInfoUpdateListener;
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.IGetMemoryBlockAddressInfoReq;
|
||||
import org.eclipse.cdt.debug.core.model.IMemoryBlockAddressInfoRetrieval.IMemoryBlockAddressInfoItem;
|
||||
import org.eclipse.cdt.debug.internal.core.CRequest;
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.debug.ui.DebugUITools;
|
||||
import org.eclipse.debug.ui.contexts.DebugContextEvent;
|
||||
import org.eclipse.debug.ui.contexts.IDebugContextListener;
|
||||
import org.eclipse.debug.ui.contexts.IDebugContextService;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||
import org.eclipse.jface.viewers.StructuredSelection;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.ui.IViewSite;
|
||||
import org.eclipse.ui.IWorkbenchPartSite;
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
public class RenderingAddressInfo extends Rendering
|
||||
implements IDebugContextListener, IAddressInfoUpdateListener {
|
||||
|
||||
private final TraditionalRendering fParent;
|
||||
/**
|
||||
* Simple tracker of selected context, to reduce the number of asynchronous calls to resolve the
|
||||
* information items related to a selected context
|
||||
*/
|
||||
private volatile Object fSelectedContext;
|
||||
private IMemoryBlockAddressInfoRetrieval fAddressInfoRetrieval = null;
|
||||
|
||||
/**
|
||||
* This maintains the full set of information items retrieved for the currently selected context. This is
|
||||
* updated each time a context selection change is detected
|
||||
*/
|
||||
private volatile IMemoryBlockAddressInfoItem[] fAddressInfoItems;
|
||||
|
||||
public RenderingAddressInfo(Composite parent, TraditionalRendering renderingParent) {
|
||||
super(parent, renderingParent);
|
||||
|
||||
fParent = renderingParent;
|
||||
// Register as Debug context listener
|
||||
IWorkbenchPartSite site = fParent.getMemoryRenderingContainer().getMemoryRenderingSite().getSite();
|
||||
DebugUITools.addPartDebugContextListener(site, this);
|
||||
|
||||
IDebugContextService contextService = DebugUITools.getDebugContextManager()
|
||||
.getContextService(site.getWorkbenchWindow());
|
||||
resolveAddressInfoForCurrentSelection(contextService);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
||||
fSelectedContext = null;
|
||||
fMapStartAddrToInfoItems.clear();
|
||||
fAddressInfoItems = null;
|
||||
|
||||
IWorkbenchPartSite site = fParent.getMemoryRenderingContainer().getMemoryRenderingSite().getSite();
|
||||
DebugUITools.removePartDebugContextListener(site, this);
|
||||
|
||||
if (fAddressInfoRetrieval != null) {
|
||||
fAddressInfoRetrieval.removeAddressInfoUpdateListener(this);
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private class GetMemoryBlockAddressInfoReq extends CRequest implements IGetMemoryBlockAddressInfoReq {
|
||||
private Map<String, IMemoryBlockAddressInfoItem[]> fInfoTypeToItems = Collections
|
||||
.synchronizedMap(new HashMap<String, IMemoryBlockAddressInfoItem[]>());
|
||||
private final Object fContext;
|
||||
|
||||
GetMemoryBlockAddressInfoReq(Object context) {
|
||||
fContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMemoryBlockAddressInfoItem[] getAddressInfoItems(String type) {
|
||||
return fInfoTypeToItems.get(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddressInfoItems(String type, IMemoryBlockAddressInfoItem[] items) {
|
||||
fInfoTypeToItems.put(type, items);
|
||||
}
|
||||
|
||||
public Object getContext() {
|
||||
return fContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAddressInfoItemTypes() {
|
||||
return fInfoTypeToItems.keySet().toArray(new String[fInfoTypeToItems.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMemoryBlockAddressInfoItem[] getAllAddressInfoItems() {
|
||||
// concatenate the different type of items received into a single list
|
||||
List<IMemoryBlockAddressInfoItem> allItemsList = new ArrayList<>();
|
||||
// For each set of items
|
||||
for (IMemoryBlockAddressInfoItem[] partialItems : fInfoTypeToItems.values()) {
|
||||
if (partialItems != null && partialItems.length > 0) {
|
||||
allItemsList.addAll(Arrays.asList(partialItems));
|
||||
}
|
||||
}
|
||||
return allItemsList.toArray(new IMemoryBlockAddressInfoItem[allItemsList.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.4
|
||||
*/
|
||||
@Override
|
||||
public void debugContextChanged(DebugContextEvent event) {
|
||||
if ((event.getFlags() & DebugContextEvent.ACTIVATED) > 0) {
|
||||
// Resolve selection
|
||||
ISelection selection = event.getContext();
|
||||
if (!(selection instanceof IStructuredSelection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object elem = ((IStructuredSelection) selection).getFirstElement();
|
||||
handleDebugContextChanged(elem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void resolveAddressInfoForCurrentSelection(IDebugContextService contextService) {
|
||||
IWorkbenchPartSite site = fParent.getMemoryRenderingContainer().getMemoryRenderingSite().getSite();
|
||||
// Check current selection
|
||||
ISelection selection = contextService.getActiveContext(site.getId(),
|
||||
((IViewSite) site).getSecondaryId());
|
||||
if (selection instanceof StructuredSelection) {
|
||||
handleDebugContextChanged(((StructuredSelection) selection).getFirstElement());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDebugContextChanged(final Object context) {
|
||||
if (isDisposed() || context == null) {
|
||||
// Invalid context or Data pane is not visible
|
||||
return;
|
||||
}
|
||||
|
||||
if (context instanceof IAdaptable) {
|
||||
IAdaptable adaptable = (IAdaptable) context;
|
||||
|
||||
final IMemoryBlockAddressInfoRetrieval addrInfo = ((IMemoryBlockAddressInfoRetrieval) adaptable
|
||||
.getAdapter(IMemoryBlockAddressInfoRetrieval.class));
|
||||
|
||||
if (addrInfo == null) {
|
||||
// No information retrieval available
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the selected context to later help us determine if the selection has really changed
|
||||
fSelectedContext = context;
|
||||
|
||||
final Display display = getDisplay();
|
||||
addrInfo.getMemoryBlockAddressInfo(context, getMemoryBlock(),
|
||||
new GetMemoryBlockAddressInfoReq(context) {
|
||||
@Override
|
||||
public void done() {
|
||||
// If the context is still valid
|
||||
if (getContext().equals(fSelectedContext)) {
|
||||
final IMemoryBlockAddressInfoItem[] addressInfoItems = getAllAddressInfoItems();
|
||||
if (!display.isDisposed()) {
|
||||
display.asyncExec(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// The selection has changed, so our Address information may no longer be valid
|
||||
fAddressInfoItems = addressInfoItems;
|
||||
fMapStartAddrToInfoItems.clear();
|
||||
|
||||
if (fBinaryPane.isVisible()) {
|
||||
redrawPanes();
|
||||
}
|
||||
|
||||
refreshUpdateListener(addrInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshUpdateListener(final IMemoryBlockAddressInfoRetrieval addrInfo) {
|
||||
if (fAddressInfoRetrieval == null) {
|
||||
// One retrieval per session,
|
||||
// Register this rendering to listen for info updates
|
||||
fAddressInfoRetrieval = addrInfo;
|
||||
addrInfo.addAddressInfoUpdateListener(RenderingAddressInfo.this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Return the view port end address, if the DataPane displays information with a single height per
|
||||
* row i.e. single height is used when no additional address information is available for any of
|
||||
* the addresses in the view port
|
||||
*/
|
||||
private BigInteger getViewportEndAddressSingleHeight() {
|
||||
int cellHeight = fBinaryPane.getCellTextHeight() + (getCellPadding() * 2);
|
||||
int rowCount = getBounds().height / cellHeight;
|
||||
BigInteger endAddress = fViewportAddress
|
||||
.add(BigInteger.valueOf(this.getBytesPerRow() * rowCount / getAddressableSize()));
|
||||
|
||||
return endAddress;
|
||||
}
|
||||
|
||||
private boolean isWithinRange(BigInteger item, BigInteger start, BigInteger end) {
|
||||
if (item.compareTo(start) > -1 && item.compareTo(end) < 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String[] orderTypesAscending(Set<String> items) {
|
||||
List<String> collection = new ArrayList<String>(items);
|
||||
Collections.sort(collection);
|
||||
return collection.toArray(new String[collection.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void redrawPanes() {
|
||||
if (!isDisposed() && this.isVisible()) {
|
||||
// Refresh address information visible in the current viewport
|
||||
getVisibleValueToAddressInfoItems();
|
||||
}
|
||||
|
||||
super.redrawPanes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAddressInfoUpdate(EventType type, Object update) {
|
||||
fAddressInfoItems = null;
|
||||
IWorkbenchPartSite site = fParent.getMemoryRenderingContainer().getMemoryRenderingSite().getSite();
|
||||
IDebugContextService contextService = DebugUITools.getDebugContextManager()
|
||||
.getContextService(site.getWorkbenchWindow());
|
||||
resolveAddressInfoForCurrentSelection(contextService);
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<BigInteger, List<IMemoryBlockAddressInfoItem>> getVisibleValueToAddressInfoItems() {
|
||||
IMemoryBlockAddressInfoItem[] items = fAddressInfoItems;
|
||||
if (items == null) {
|
||||
fMapStartAddrToInfoItems.clear();
|
||||
return fMapStartAddrToInfoItems;
|
||||
}
|
||||
|
||||
if (getRadix() != RADIX_HEX && getRadix() != RADIX_BINARY) {
|
||||
// If not using Hex or Binary radix, we can not accurately determine the location of cross
|
||||
// reference information
|
||||
// unless the cell size matches the addressable size of the target system
|
||||
if (fParent.getAddressableSize() != getBytesPerColumn()) {
|
||||
fMapStartAddrToInfoItems.clear();
|
||||
return fMapStartAddrToInfoItems;
|
||||
}
|
||||
}
|
||||
|
||||
Map<BigInteger, List<IMemoryBlockAddressInfoItem>> allValuesMap = new HashMap<>(items.length);
|
||||
|
||||
// This local variable will hold the same values as the instance variable fMapAddressToInfoItems, and
|
||||
// be used as
|
||||
// return value. The reason for the duplication is to prevent concurrent access exceptions
|
||||
Map<BigInteger, List<IMemoryBlockAddressInfoItem>> filteredValuesMap = new HashMap<>(items.length);
|
||||
|
||||
synchronized (fMapStartAddrToInfoItems) {
|
||||
// Refreshing the Address to InfoItem data map
|
||||
fMapStartAddrToInfoItems.clear();
|
||||
BigInteger startAddress = getViewportStartAddress();
|
||||
// Get the endAddress considering a page that uses single height,
|
||||
// Note: The UI may some times present rows with double height even if the user does not see items
|
||||
// with additional info, the reason is that the second part of a view port page may contain all
|
||||
// the items with info.
|
||||
// if we were to use and endAddress for a page that uses double height, but end up not having
|
||||
// items with additional information, then it would need to switch to single height to compact the
|
||||
// information in the view but since an endAddress for double height was used it will not consider
|
||||
// half of the items for additional information, so marking info. would not be shown.
|
||||
BigInteger endAddress = getViewportEndAddressSingleHeight();
|
||||
|
||||
for (IMemoryBlockAddressInfoItem item : items) {
|
||||
List<IMemoryBlockAddressInfoItem> containers = allValuesMap.get(item.getAddress());
|
||||
if (containers == null) {
|
||||
containers = new ArrayList<>();
|
||||
allValuesMap.put(item.getAddress(), containers);
|
||||
}
|
||||
containers.add(item);
|
||||
|
||||
// If any address within the item width is within the visible range we want it in the filtered
|
||||
// result
|
||||
BigInteger itemStart = item.getAddress();
|
||||
BigInteger itemEnd = item.getAddress().add(item.getRangeInAddressableUnits());
|
||||
boolean itemStartIsInRange = isWithinRange(itemStart, startAddress, endAddress);
|
||||
boolean itemEndIsInRange = isWithinRange(itemEnd, startAddress, endAddress);
|
||||
boolean itemSpansOverVisibleRange = isWithinRange(startAddress, itemStart, itemEnd)
|
||||
&& isWithinRange(endAddress, itemStart, itemEnd);
|
||||
|
||||
if (itemStartIsInRange || itemEndIsInRange || itemSpansOverVisibleRange) {
|
||||
fMapStartAddrToInfoItems.put(item.getAddress(), allValuesMap.get(item.getAddress()));
|
||||
filteredValuesMap.put(item.getAddress(), allValuesMap.get(item.getAddress()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filteredValuesMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
String buildAddressInfoString(BigInteger cellAddress, String separator, boolean addTypeHeaders) {
|
||||
List<IMemoryBlockAddressInfoItem> infoItems = fMapStartAddrToInfoItems.get(cellAddress);
|
||||
|
||||
if (infoItems == null || infoItems.size() < 1) {
|
||||
// No information to display
|
||||
return "";
|
||||
}
|
||||
|
||||
// The container string builder for all types
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Map<String, StringBuilder> infoTypeToStringBuilder = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < infoItems.size(); i++) {
|
||||
String infoType = infoItems.get(i).getInfoType();
|
||||
|
||||
// Resolve string builder for this info type
|
||||
StringBuilder typeBuilder = infoTypeToStringBuilder.get(infoType);
|
||||
if (typeBuilder == null) {
|
||||
// Create a String builder per information type
|
||||
if (addTypeHeaders) {
|
||||
typeBuilder = new StringBuilder(infoType).append(":").append(separator);
|
||||
} else {
|
||||
typeBuilder = new StringBuilder();
|
||||
}
|
||||
infoTypeToStringBuilder.put(infoType, typeBuilder);
|
||||
}
|
||||
|
||||
// append the new item information to the string builder associated to its type
|
||||
typeBuilder.append(infoItems.get(i).getLabel()).append(separator);
|
||||
}
|
||||
|
||||
// Present the group of items sorted by type name
|
||||
String[] sortedTypes = orderTypesAscending(infoTypeToStringBuilder.keySet());
|
||||
|
||||
// Consolidate the String builders per type into a single one
|
||||
int i = 0;
|
||||
for (String type : sortedTypes) {
|
||||
StringBuilder builder = infoTypeToStringBuilder.get(type);
|
||||
String text = builder.toString();
|
||||
text = text.substring(0, text.length() - 1);
|
||||
sb.append(text);
|
||||
if (i < infoTypeToStringBuilder.keySet().size() - 1) {
|
||||
sb.append(separator);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasAddressInfo(BigInteger cellAddress) {
|
||||
return fMapStartAddrToInfoItems.keySet().contains(cellAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if additional address information is available to display in the current visible range
|
||||
*/
|
||||
@Override
|
||||
boolean hasVisibleRangeInfo() {
|
||||
return (fBinaryPane.fPaneVisible && fMapStartAddrToInfoItems.size() > 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -238,7 +238,7 @@ public class TextPane extends AbstractPane
|
|||
{
|
||||
BigInteger start = fRendering.getViewportStartAddress();
|
||||
|
||||
for(int i = 0; i < this.getBounds().height / cellHeight; i++)
|
||||
for(int i = 0; i < fRendering.getRowCount(); i++)
|
||||
{
|
||||
for(int col = 0; col < columns; col++)
|
||||
{
|
||||
|
|
|
@ -428,7 +428,7 @@ public class TraditionalRendering extends AbstractMemoryRendering implements IRe
|
|||
{
|
||||
allocateColors();
|
||||
|
||||
this.fRendering = new Rendering(parent, this);
|
||||
this.fRendering = new RenderingAddressInfo(parent, this);
|
||||
|
||||
applyPreferences();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue