/******************************************************************************* * 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()]); } }