/******************************************************************************* * Copyright (c) 2012, 2015 Tilera Corporation 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: * William R. Swanson (Tilera Corporation) - initial API and implementation * Marc Dumais (Ericsson) - Add CPU/core load information to the multicore visualizer (Bug 396268) * Xavier Raynaud (Kalray) - Bug 431935 * Alvaro Sanchez-Leon (Ericsson) - Bug 459114 - override construction of the data model *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.utils; import java.util.ArrayList; import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateCountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IProcesses; import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext; import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMData; import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMData; import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMData2; import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason; 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.IFrameDMData; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.gdb.multicorevisualizer.internal.ui.model.VisualizerExecutionState; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICPUDMContext; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.ICoreDMContext; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS.IHardwareTargetDMContext; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2; import org.eclipse.cdt.dsf.gdb.service.IGDBHardwareAndOS2.ILoadInfo; import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses.IGdbThreadDMData; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; /** Debugger state information accessors.</br> * * NOTE: The methods on this class perform asynchronous operations * and the result is reported back via the received request monitor */ public class DSFDebugModel implements IDSFTargetDataProxy { // --- static methods --- @Override @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") public void getCPUs(DSFSessionState sessionState, final DataRequestMonitor<ICPUDMContext[]> rm) { ICommandControlService controlService = sessionState.getService(ICommandControlService.class); IGDBHardwareAndOS hwService = sessionState.getService(IGDBHardwareAndOS.class); if (controlService == null || hwService == null) { rm.done(new ICPUDMContext[0]); return; } IHardwareTargetDMContext contextToUse = DMContexts.getAncestorOfType(controlService.getContext(), IHardwareTargetDMContext.class); hwService.getCPUs(contextToUse, new ImmediateDataRequestMonitor<ICPUDMContext[]>(rm) { @Override protected void handleCompleted() { ICPUDMContext[] cpuContexts; if (isSuccess()) { cpuContexts = getData(); } else { cpuContexts = new ICPUDMContext[0]; } rm.done(cpuContexts); } }); } @Override @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") public void getLoad(DSFSessionState sessionState, final IDMContext context, final DataRequestMonitor<ILoadInfo> rm) { IGDBHardwareAndOS2 hwService = sessionState.getService(IGDBHardwareAndOS2.class); if (hwService == null) { rm.setData(null); rm.done(); return; } hwService.getLoadInfo(context, rm); } @Override @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") public void getCores(DSFSessionState sessionState, final DataRequestMonitor<ICoreDMContext[]> rm) { getCores(sessionState, null, rm); } @Override @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") public void getCores(DSFSessionState sessionState, final ICPUDMContext cpuContext, final DataRequestMonitor<ICoreDMContext[]> rm) { IGDBHardwareAndOS hwService = sessionState.getService(IGDBHardwareAndOS.class); if (hwService == null) { rm.done(new ICoreDMContext[0]); return; } IDMContext targetContextToUse = cpuContext; if (targetContextToUse == null) { // if caller doesn't supply a specific cpu context, // use the hardware context (so we get all available cores) ICommandControlService controlService = sessionState.getService(ICommandControlService.class); targetContextToUse = DMContexts.getAncestorOfType(controlService.getContext(), IHardwareTargetDMContext.class); } hwService.getCores(targetContextToUse, new ImmediateDataRequestMonitor<ICoreDMContext[]>() { @Override protected void handleCompleted() { ICoreDMContext[] coreContexts = getData(); if (!isSuccess() || coreContexts == null || coreContexts.length < 1) { // Unable to get any core data rm.done(new ICoreDMContext[0]); } else { rm.done(coreContexts); } } } ); } @Override @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") public void getThreads(DSFSessionState sessionState, final ICPUDMContext cpuContext, final ICoreDMContext coreContext, final DataRequestMonitor<IDMContext[]> rm) { // Get control DM context associated with the core // Process/Thread Info service (GDBProcesses_X_Y_Z) final IProcesses procService = sessionState.getService(IProcesses.class); // Debugger control context (GDBControlDMContext) ICommandControlDMContext controlContext = DMContexts.getAncestorOfType(coreContext, ICommandControlDMContext.class); if (procService == null || controlContext == null) { rm.done(new IDMContext[0]); return; } // Get debugged processes procService.getProcessesBeingDebugged(controlContext, new ImmediateDataRequestMonitor<IDMContext[]>() { @Override protected void handleCompleted() { IDMContext[] processContexts = getData(); if (!isSuccess() || processContexts == null || processContexts.length < 1) { // Unable to get any process data for this core // Is this an issue? A core may have no processes/threads, right? rm.done(new IDMContext[0]); return; } final ArrayList<IDMContext> threadContextsList = new ArrayList<>(); final ImmediateCountingRequestMonitor crm1 = new ImmediateCountingRequestMonitor( new ImmediateRequestMonitor() { @Override protected void handleCompleted() { IDMContext[] threadContexts = threadContextsList.toArray(new IDMContext[threadContextsList.size()]); rm.done(threadContexts); } }); crm1.setDoneCount(processContexts.length); for (IDMContext processContext : processContexts) { IContainerDMContext containerContext = DMContexts.getAncestorOfType(processContext, IContainerDMContext.class); procService.getProcessesBeingDebugged(containerContext, new ImmediateDataRequestMonitor<IDMContext[]>(crm1) { @Override protected void handleCompleted() { IDMContext[] threadContexts = getData(); if (!isSuccess() || threadContexts == null || threadContexts.length < 1) { crm1.done(); return; } final ImmediateCountingRequestMonitor crm2 = new ImmediateCountingRequestMonitor(crm1); crm2.setDoneCount(threadContexts.length); for (final IDMContext threadContext : threadContexts) { IThreadDMContext threadContext2 = DMContexts.getAncestorOfType(threadContext, IThreadDMContext.class); procService.getExecutionData(threadContext2, new ImmediateDataRequestMonitor<IThreadDMData>(crm2) { @Override protected void handleCompleted() { IThreadDMData data = getData(); // Check whether we know about cores if (data != null && data instanceof IGdbThreadDMData) { String[] cores = ((IGdbThreadDMData)data).getCores(); if (cores != null && cores.length == 1) { if (coreContext.getId().equals(cores[0])) { // This thread belongs to the proper core threadContextsList.add(threadContext); } } } crm2.done(); } } ); } } } ); } } } ); } @Override @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") public void getThreadData(DSFSessionState sessionState, final ICPUDMContext cpuContext, final ICoreDMContext coreContext, final IMIExecutionDMContext execContext, final DataRequestMonitor<IThreadDMData> rm) { IProcesses procService = sessionState.getService(IProcesses.class); if (procService == null) { rm.setData(null); rm.done(); return; } final IThreadDMContext threadContext = DMContexts.getAncestorOfType(execContext, IThreadDMContext.class); procService.getExecutionData(threadContext, rm); } @Override @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") public void getTopFrameData(final DSFSessionState sessionState, final IMIExecutionDMContext execContext, final DataRequestMonitor<IFrameDMData> rm) { final IFrameDMData nullFrameData = null; // For a suspended thread, retrieve the current stack final IStack stackService = sessionState.getService(IStack.class); if (stackService != null) { stackService.getTopFrame(execContext, new ImmediateDataRequestMonitor<IFrameDMContext>(null) { @Override protected void handleCompleted() { IFrameDMContext targetFrameContext = isSuccess() ? getData() : null; if (targetFrameContext != null) { stackService.getFrameData(targetFrameContext, new ImmediateDataRequestMonitor<IFrameDMData>(null) { @Override protected void handleCompleted() { IFrameDMData frameData = isSuccess() ? getData() : null; rm.done(frameData); } }); } else { rm.done(nullFrameData); } } }); } else { rm.done(nullFrameData); } } @Override @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") public void getThreadExecutionState(final DSFSessionState sessionState, final ICPUDMContext cpuContext, final ICoreDMContext coreContext, final IMIExecutionDMContext execContext, final IThreadDMData threadData, final DataRequestMonitor<VisualizerExecutionState> rm) { IRunControl runControl = sessionState.getService(IRunControl.class); if (runControl == null) { rm.setData(null); rm.done(); return; } if (runControl.isSuspended(execContext) == false) { // The thread is running rm.done(VisualizerExecutionState.RUNNING); } else { getThreadSuspendReason(sessionState, execContext, rm); } } /** For a suspended thread, let's see why it is suspended, * to find out if the thread is crashed */ @ConfinedToDsfExecutor("sessionState.getDsfSession().getExecutor()") private static void getThreadSuspendReason(DSFSessionState sessionState, IMIExecutionDMContext execContext, final DataRequestMonitor<VisualizerExecutionState> rm) { IRunControl runControl = sessionState.getService(IRunControl.class); if (runControl != null) { runControl.getExecutionData(execContext, new ImmediateDataRequestMonitor<IExecutionDMData>() { @Override protected void handleCompleted() { IExecutionDMData executionData = getData(); VisualizerExecutionState state = VisualizerExecutionState.SUSPENDED; if (isSuccess() && executionData != null) { if (executionData.getStateChangeReason() == StateChangeReason.SIGNAL) { if (executionData instanceof IExecutionDMData2) { String details = ((IExecutionDMData2) executionData).getDetails(); if (details != null) { if (isCrashSignal(details)) { state = VisualizerExecutionState.CRASHED; } } } } } rm.done(state); } }); } else { rm.setData(null); rm.done(); } } /** * Return true if the string SIGNALINFO describes a signal * that indicates a crash. */ public static boolean isCrashSignal(String signalInfo) { if (signalInfo.startsWith("SIGHUP") || //$NON-NLS-1$ signalInfo.startsWith("SIGILL") || //$NON-NLS-1$ signalInfo.startsWith("SIGABRT") || //$NON-NLS-1$ signalInfo.startsWith("SIGBUS") || //$NON-NLS-1$ signalInfo.startsWith("SIGSEGV")) { //$NON-NLS-1$ // Not sure about the list of events here... // We are dealing with a crash return true; } return false; } }