/******************************************************************************* * 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.GdbMemoryAddressInfoRegistersRetrieval; 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), new GdbMemoryAddressInfoRegistersRetrieval(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); } } } }