diff options
Diffstat (limited to 'lttng/org.eclipse.linuxtools.gdbtrace.core/src/org/eclipse/linuxtools/internal/gdbtrace/core/trace/DsfGdbAdaptor.java')
-rw-r--r-- | lttng/org.eclipse.linuxtools.gdbtrace.core/src/org/eclipse/linuxtools/internal/gdbtrace/core/trace/DsfGdbAdaptor.java | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/lttng/org.eclipse.linuxtools.gdbtrace.core/src/org/eclipse/linuxtools/internal/gdbtrace/core/trace/DsfGdbAdaptor.java b/lttng/org.eclipse.linuxtools.gdbtrace.core/src/org/eclipse/linuxtools/internal/gdbtrace/core/trace/DsfGdbAdaptor.java new file mode 100644 index 0000000000..301ba61e9f --- /dev/null +++ b/lttng/org.eclipse.linuxtools.gdbtrace.core/src/org/eclipse/linuxtools/internal/gdbtrace/core/trace/DsfGdbAdaptor.java @@ -0,0 +1,829 @@ +/******************************************************************************* + * Copyright (c) 2011, 2013 Ericsson + * + * 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: + * Marc Dumais - Initial implementation + * Francois Chouinard - Misc improvements, DSF signal handling, dynamic experiment + * Patrick Tasse - Updated for TMF 2.0 + * Bernd Hufmann - Fixed deadlock during shutdown + *******************************************************************************/ + +package org.eclipse.linuxtools.internal.gdbtrace.core.trace; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +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.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; +import org.eclipse.cdt.dsf.gdb.service.GDBTraceControl_7_2.TraceRecordSelectedChangedEvent; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordDMContext; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordDMData; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceStatusDMData; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext; +import org.eclipse.cdt.dsf.mi.service.IMICommandControl; +import org.eclipse.cdt.dsf.mi.service.IMIProcesses; +import org.eclipse.cdt.dsf.mi.service.MIBreakpointDMData; +import org.eclipse.cdt.dsf.mi.service.MIBreakpoints; +import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; +import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.ILaunchesListener2; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer; +import org.eclipse.debug.ui.AbstractDebugView; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.debug.ui.contexts.DebugContextEvent; +import org.eclipse.debug.ui.contexts.IDebugContextListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.linuxtools.internal.gdbtrace.core.GdbTraceCorePlugin; +import org.eclipse.linuxtools.internal.gdbtrace.core.event.GdbTraceEvent; +import org.eclipse.linuxtools.internal.gdbtrace.core.event.GdbTraceEventContent; +import org.eclipse.linuxtools.tmf.core.event.ITmfEventType; +import org.eclipse.linuxtools.tmf.core.event.TmfEventField; +import org.eclipse.linuxtools.tmf.core.event.TmfEventType; +import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp; +import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace; +import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment; +import org.eclipse.linuxtools.tmf.ui.editors.ITmfTraceEditor; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE; + +/** + * Adaptor to access GDB Tracepoint frames, previously collected and saved in a + * file by GDB. One instance of this maps to a single DSF-GDB session. + * <p> + * This class offers the functions of starting a post-mortem GDB session with a + * tracepoint data file, navigate the data frames and return the data contained + * in a given tracepoint frame. + * <p> + * Note: GDB 7.2 or later is required to handle tracepoints + * + * @author Marc Dumais + * @author Francois Chouinard + */ +@SuppressWarnings("restriction") +public class DsfGdbAdaptor { + + private GdbTrace fGdbTrace; + + private int fNumberOfFrames = 0; + + private ILaunch fLaunch; + private boolean isTerminating; + private DsfSession fDsfSession = null; + private String fSessionId; + + private String tracedExecutable = ""; //$NON-NLS-1$ + + private String gdb72Executable = ""; //$NON-NLS-1$ + private String fTraceFilePath = ""; //$NON-NLS-1$ + private String fTraceFile = ""; //$NON-NLS-1$ + private String sourceLocator = ""; //$NON-NLS-1$ + + // To save tracepoints detailed info. The key is the rank of the + // breakpoint (tracepoint is a kind of breakpoint) + private Map<Integer, MIBreakpointDMData> fTpInfo = new HashMap<Integer, MIBreakpointDMData>(); + + private TmfEventType tmfEventType = new TmfEventType(ITmfEventType.DEFAULT_CONTEXT_ID, "GDB Tracepoint", TmfEventField.makeRoot(new String[] { "Content" })); //$NON-NLS-1$ //$NON-NLS-2$ + + @SuppressWarnings("unused") + private static DsfGdbPlatformEventListener fPlatformEventListener = new DsfGdbPlatformEventListener(); + + /** + * <b><u>DsfGdbPlatformEventListener</u></b> + * <p> + * Listens to platform and DSF-GDB events that announce important events + * about the launchers or a change in debug context that we might need to + * react-to. + * <p> + * @author Francois Chouinard + */ + private static class DsfGdbPlatformEventListener implements + ILaunchesListener2, IDebugContextListener { + + /** + * + */ + public DsfGdbPlatformEventListener() { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + DebugPlugin.getDefault().getLaunchManager().addLaunchListener(DsfGdbPlatformEventListener.this); + IWorkbench wb = PlatformUI.getWorkbench(); + IWorkbenchWindow win = wb.getActiveWorkbenchWindow(); + DebugUITools.getDebugContextManager().getContextService(win).addDebugContextListener(DsfGdbPlatformEventListener.this); + } + }); + } + + @Override + public synchronized void launchesRemoved(ILaunch[] launches) { + } + + @Override + public synchronized void launchesAdded(ILaunch[] launches) { + } + + @Override + public synchronized void launchesChanged(ILaunch[] launches) { + } + + @Override + public synchronized void launchesTerminated(ILaunch[] launches) { + for (ILaunch launch : launches) { + String sessionId = ((GdbLaunch) launch).getSession().getId(); + closeGdbTraceEditor(sessionId); + } + } + + private String fCurrentSessionId = ""; //$NON-NLS-1$ + @Override + public void debugContextChanged(DebugContextEvent event) { + ISelection selection = event.getContext(); + if (selection instanceof IStructuredSelection) { + List<?> eventContextList = ((IStructuredSelection) selection).toList(); + for (Object eventContext : eventContextList) { + if (eventContext instanceof IAdaptable) { + IDMContext context = (IDMContext) ((IAdaptable) eventContext).getAdapter(IDMContext.class); + if (context != null) { + String sessionId; + synchronized(fCurrentSessionId) { + sessionId = context.getSessionId(); + if (sessionId.equals(fCurrentSessionId)) { + return; + } + } + fCurrentSessionId = sessionId; + // Get the current trace record + final DsfExecutor executor = DsfSession.getSession(sessionId).getExecutor(); + final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), sessionId); + Query<ITraceRecordDMContext> getCurrentRecordQuery = new Query<ITraceRecordDMContext>() { + @Override + public void execute(final DataRequestMonitor<ITraceRecordDMContext> queryRm) { + final IGDBTraceControl traceControl = tracker.getService(IGDBTraceControl.class); + final ICommandControlService commandControl = tracker.getService(ICommandControlService.class); + if (traceControl != null && commandControl != null) { + ITraceTargetDMContext traceContext = (ITraceTargetDMContext) commandControl.getContext(); + traceControl.getCurrentTraceRecordContext(traceContext, queryRm); + } else { + queryRm.done(); + } + } + }; + try { + executor.execute(getCurrentRecordQuery); + ITraceRecordDMContext record = getCurrentRecordQuery.get(); + // If we get a trace record, it means that this can be used + if (record != null && record.getRecordId() != null) { + int recordId = Integer.parseInt(record.getRecordId()); + selectGdbTraceEditor(sessionId, recordId); + break; + } + } catch (InterruptedException e) { + } catch (java.util.concurrent.ExecutionException e) { + } catch (RejectedExecutionException e) { + } finally { + tracker.dispose(); + } + // else not DSF-GDB or GDB < 7.2 + } + } + // else not DSF + } + } + } + } // class DsfGdbPlatformEventListener + + /** + * Constructor for DsfGdbAdaptor. This is used when we want to launch a + * DSF-GDB session and use it as source in our tracing perspective. + * i.e. when launching from the Project Explorer + * + * @param trace the GDB trace + * @param gdbExec GDB executable. Must be version 7.2 or later. + * @param traceFile previously generated GDB tracepoint file + * @param tracedExecutable executable that was used to generate the tracefile + * workspace, where the traced executable was taken from. + */ + public DsfGdbAdaptor(GdbTrace trace, String gdbExec, String traceFile, String tracedExecutable) { + this.fGdbTrace = trace; + this.gdb72Executable = gdbExec; + this.fTraceFilePath = traceFile; + this.fTraceFile = traceFile.substring(traceFile.lastIndexOf(IPath.SEPARATOR) + 1); + this.tracedExecutable = tracedExecutable; + + try { + launchDGBPostMortemTrace(); + } catch (CoreException e) { + e.printStackTrace(); + } + } + + /** + * Builds a launcher and launches a Post-mortem GDB session, based on a + * previously-gathered GDB Tracepoint file. The information used to + * create the launcher is provided to the constructor of this class, + * at instantiation time. + * <p> + * Note: Requires GDB 7.2 or later + */ + private void launchDGBPostMortemTrace() throws CoreException { + + ILaunchConfigurationType configType = DebugPlugin + .getDefault() + .getLaunchManager() + .getLaunchConfigurationType("org.eclipse.cdt.launch.postmortemLaunchType"); //$NON-NLS-1$ + ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, fTraceFile); + + wc.setAttribute("org.eclipse.cdt.dsf.gdb.DEBUG_NAME", gdb72Executable); //$NON-NLS-1$ + wc.setAttribute("org.eclipse.cdt.dsf.gdb.POST_MORTEM_TYPE", "TRACE_FILE"); //$NON-NLS-1$ //$NON-NLS-2$ + wc.setAttribute("org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR", 0); //$NON-NLS-1$ + wc.setAttribute("org.eclipse.cdt.launch.COREFILE_PATH", fTraceFilePath); //$NON-NLS-1$ + wc.setAttribute("org.eclipse.cdt.launch.DEBUGGER_START_MODE", "core"); //$NON-NLS-1$ //$NON-NLS-2$ + wc.setAttribute("org.eclipse.cdt.launch.PROGRAM_NAME", tracedExecutable); //$NON-NLS-1$ + // So that the GDB launch is synchronous + wc.setAttribute("org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND", false); //$NON-NLS-1$ + + if (!sourceLocator.isEmpty()) { + wc.setAttribute("org.eclipse.debug.core.source_locator_memento", sourceLocator); //$NON-NLS-1$ + } + + // Launch GDB session + fLaunch = wc.doSave().launch("debug", null); //$NON-NLS-1$ + isTerminating = false; + + if (fLaunch instanceof GdbLaunch) { + fSessionId = ((GdbLaunch) fLaunch).getSession().getId(); + } + + fDsfSession = ((GdbLaunch) fLaunch).getSession(); + fDsfSession.addServiceEventListener(this, null); + + // Find the number of frames contained in the tracepoint file + fNumberOfFrames = findNumFrames(); + } + + /** + * This method terminates the current DSF-GDB session + */ + public void dispose() { + if (fLaunch != null && fLaunch.canTerminate() && !isTerminating) { + isTerminating = true; + try { + fLaunch.terminate(); + } catch (DebugException e) { + e.printStackTrace(); + } + fLaunch = null; + } + } + + /** + * This method will try (once per call) to get the number of GDB tracepoint + * frames for the current session, from DSF-GDB, until it succeeds at + * getting an amount different than zero. + * + * @return The number of frames in current session or zero if unsuccessful + */ + public int getNumberOfFrames() { + if (fNumberOfFrames == 0) { + fNumberOfFrames = findNumFrames(); + } + return fNumberOfFrames; + } + + + /** + * Wrapper around the selecting of a frame and the reading of its + * information. this is a work-around for the potential problem of + * concurrent access to these functions by more than one thread, + * where two clients might interfere with each other. + * <p> + * Note: We also try to get the tracepoint info here, if it's not + * already filled-in. + * + * @param rank a long corresponding to the number of the frame to be + * selected and read + * @return A GdbTraceEvent object, or null in case of failure. + */ + public synchronized GdbTraceEvent selectAndReadFrame(final long rank) { + // lazy init of tracepoints info + if(fTpInfo.isEmpty()) { + getTracepointInfo(); + } + if (selectDataFrame(rank, false)) { + GdbTraceEvent event = getTraceFrameData(rank); + long ts = event.getTimestamp().getValue(); + if (ts == rank) { + return event; + } + } + return null; + } + + + /** + * This class implements a best-effort look-up of the detailed tracepoint + * information (source code filename, line number, etc...). + */ + private void getTracepointInfo() { + + // Get the latest executor/service tracker + final DsfExecutor executor = DsfSession.getSession(fSessionId).getExecutor(); + final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId); + + Query<Object> selectRecordQuery = new Query<Object>() { + @Override + public void execute(final DataRequestMonitor<Object> drm) { + + // A breakpoint is no longer GDB-global but tied to a specific process + // So we need to find our process and the ask for its breakpoints + IMIProcesses procService = tracker.getService(IMIProcesses.class); + final ICommandControlService cmdControl = tracker.getService(ICommandControlService.class); + if (procService == null || cmdControl == null) { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Could not find necessary services", null)); //$NON-NLS-1$ + drm.done(); + return; + } + + ITraceTargetDMContext context = (ITraceTargetDMContext) cmdControl.getContext(); + ICommandControlDMContext cmdControlDMC = DMContexts.getAncestorOfType(context, ICommandControlDMContext.class); + + procService.getProcessesBeingDebugged( + cmdControlDMC, + new DataRequestMonitor<IDMContext[]>(executor, drm) { + @Override + protected void handleSuccess() { + assert getData() != null; + assert getData().length == 1; + if (getData() == null || getData().length < 1) { + drm.done(); + return; + } + + // Choose the first process for now, until gdb can tell + // us which process the trace record is associated with. + IContainerDMContext containerDMC = (IContainerDMContext)(getData()[0]); + IBreakpointsTargetDMContext bpTargetDMC = DMContexts.getAncestorOfType(containerDMC , IBreakpointsTargetDMContext.class); + + CommandFactory cmdFactory = tracker.getService(IMICommandControl.class).getCommandFactory(); + IBreakpoints bpService = tracker.getService(MIBreakpoints.class); + if (cmdFactory == null || bpService == null) { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Could not find necessary services", null)); //$NON-NLS-1$ + drm.done(); + return; + } + + // Execute the command + cmdControl.queueCommand(cmdFactory.createMIBreakList(bpTargetDMC), + new DataRequestMonitor<MIBreakListInfo>(executor, drm) { + @Override + protected void handleSuccess() { + MIBreakpoint[] breakpoints = getData().getMIBreakpoints(); + for (int i = 0; i < breakpoints.length; i++) { + MIBreakpointDMData breakpoint = new MIBreakpointDMData(breakpoints[i]); + String type = breakpoint.getBreakpointType(); + // Only save info if the current breakpoint is of type tracepoint + if(type.compareTo(MIBreakpoints.TRACEPOINT) == 0 ) { + fTpInfo.put(new Integer(breakpoint.getReference()), breakpoint); + } + } + drm.done(); + } + }); + } + }); + } + }; + try { + executor.execute(selectRecordQuery); + selectRecordQuery.get(); // blocks + } catch (RejectedExecutionException e) { + + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + tracker.dispose(); + } + } + + /** + * Returns the number of frames contained in currently loaded tracepoint GDB + * session. + * <p> + * Note: A postmortem GDB session must be started before calling + * this method + * + * @return the number of frames contained in currently loaded tracepoint GDB + * session or zero in case of error + */ + private synchronized int findNumFrames() { + int frameNum = 0; + + if (DsfSession.getSession(fSessionId) == null) { + return 0; + } + + final DsfExecutor executor = DsfSession.getSession(fSessionId) + .getExecutor(); + final DsfServicesTracker tracker = new DsfServicesTracker( + GdbTraceCorePlugin.getBundleContext(), fSessionId); + + Query<ITraceStatusDMData> selectRecordQuery = new Query<ITraceStatusDMData>() { + @Override + public void execute( + final DataRequestMonitor<ITraceStatusDMData> queryRm) { + final IGDBTraceControl traceControl = tracker + .getService(IGDBTraceControl.class); + + final ICommandControlService commandControl = tracker + .getService(ICommandControlService.class); + final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl + .getContext(); + + if (traceControl != null) { + traceControl.getTraceStatus(dmc, queryRm); + } else { + queryRm.done(); + } + } + }; + try { + executor.execute(selectRecordQuery); + ITraceStatusDMData data = selectRecordQuery.get(); // blocks + frameNum = data.getNumberOfCollectedFrame(); + } catch (InterruptedException e) { + + } catch (java.util.concurrent.ExecutionException e) { + + } catch (RejectedExecutionException e) { + + } finally { + tracker.dispose(); + } + return frameNum; + } + + /** + * This method uses the DSF-GDB interface to select a given frame number + * in the current GDB tracepoint session. + * + * @param rank the rank of the tracepoint frame to select. + * @param update true if visualization should be updated + * @return boolean true if select worked. + */ + public boolean selectDataFrame(final long rank, final boolean update) { + boolean status = true; + + final DsfSession dsfSession = DsfSession.getSession(fSessionId); + if (dsfSession == null) { + return false; + } + + if (update) { + /* + * Clear the selection to ensure that the new selection is not + * prevented from overriding the current selection by the DSF + * selection policy. This could be removed when DSF provides + * an API to force the trace record selection in the Debug view. + */ + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + for (IWorkbenchWindow wbWindow : PlatformUI.getWorkbench().getWorkbenchWindows()) { + for (IWorkbenchPage wbPage : wbWindow.getPages()) { + IViewPart vp = wbPage.findView(IDebugUIConstants.ID_DEBUG_VIEW); + if (vp instanceof AbstractDebugView) { + Viewer viewer = ((AbstractDebugView) vp).getViewer(); + if (viewer instanceof ITreeModelViewer) { + ((ITreeModelViewer) viewer).setSelection(StructuredSelection.EMPTY, false, true); + } + } + } + } + } + }); + } + + final DsfExecutor executor = dsfSession.getExecutor(); + final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId); + + Query<Object> selectRecordQuery = new Query<Object>() { + @Override + public void execute(final DataRequestMonitor<Object> queryRm) { + final IGDBTraceControl traceControl = tracker.getService(IGDBTraceControl.class); + + final ICommandControlService commandControl = tracker.getService(ICommandControlService.class); + final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl.getContext(); + + if (traceControl != null) { + ITraceRecordDMContext newCtx = traceControl.createTraceRecordContext(dmc, Integer.toString((int) rank)); + if (update) { + dsfSession.dispatchEvent(new TraceRecordSelectedChangedEvent(newCtx), new Hashtable<String, String>()); + } + traceControl.selectTraceRecord(newCtx, queryRm); + } else { + queryRm.done(); + } + } + }; + try { + executor.execute(selectRecordQuery); + selectRecordQuery.get(); // blocks + } catch (InterruptedException e) { + status = false; + } catch (java.util.concurrent.ExecutionException e) { + status = false; + } catch (RejectedExecutionException e) { + status = false; + } finally { + tracker.dispose(); + } + return status; + } + + /** + * This method uses DSF-GDB to read the currently selected GDB tracepoint + * data frame. An object of type GdbTraceEvent is build based on the + * information contained in the data frame and returned to the caller. + * <p> + * NOTE : A frame must be selected before calling this method! + * + * @param rank for internal purposes - does <b>not</b> control which + * frame will be read! + * @return parsed tp frame, in the form of a GdbTraceEvent + */ + private GdbTraceEvent getTraceFrameData(final long rank) { + + if (DsfSession.getSession(fSessionId) == null) { + return null; + } + + final DsfExecutor executor = DsfSession.getSession(fSessionId).getExecutor(); + final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId); + + Query<ITraceRecordDMData> getFrameDataQuery = new Query<ITraceRecordDMData>() { + @Override + public void execute(final DataRequestMonitor<ITraceRecordDMData> rm) { + final IGDBTraceControl traceControl = tracker.getService(IGDBTraceControl.class); + + final ICommandControlService commandControl = tracker.getService(ICommandControlService.class); + final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl.getContext(); + + if (traceControl != null) { + traceControl.getCurrentTraceRecordContext(dmc, + new DataRequestMonitor<ITraceRecordDMContext>(executor, rm) { + @Override + protected void handleSuccess() { + traceControl.getTraceRecordData(getData(), rm); + } + }); + } else { + rm.done(); + } + } + }; + try { + // Execute the above query + executor.execute(getFrameDataQuery); + ITraceRecordDMData data = getFrameDataQuery.get(); // blocking call + + if (data == null) { + return null; + } + + String ts = data.getTimestamp(); + if (ts == null) { + ts = "0"; //$NON-NLS-1$ + } + + // get corresponding TP data + String tmfEventRef; + MIBreakpointDMData bp = fTpInfo.get(Integer.valueOf(data.getTracepointNumber())); + if (bp != null) { + tmfEventRef = bp.getFileName() + ":" + bp.getLineNumber() + " :: " + bp.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$ + } + else { + tmfEventRef = tracedExecutable; + } + + GdbTraceEventContent evContent = new GdbTraceEventContent( + data.getContent(), + Integer.parseInt(data.getTracepointNumber()), + Integer.parseInt(data.getRecordId())); + + GdbTraceEvent ev = new GdbTraceEvent(fGdbTrace, + new TmfTimestamp(Integer.parseInt(data.getRecordId())), + "Tracepoint: " + data.getTracepointNumber() + ", Frame: " + data.getRecordId(), //$NON-NLS-1$ //$NON-NLS-2$ + tmfEventType, + evContent, + tmfEventRef); + + return ev; + + } catch (InterruptedException e) { + return createExceptionEvent(rank, "Interruption exception"); //$NON-NLS-1$ + } catch (java.util.concurrent.ExecutionException e) { + return createExceptionEvent(rank, "GDB exception"); //$NON-NLS-1$ + } catch (RejectedExecutionException e) { + return createExceptionEvent(rank, "Request rejected exception"); //$NON-NLS-1$ + } catch (Exception e) { + return createExceptionEvent(rank, "General exception"); //$NON-NLS-1$ + } + + finally { + tracker.dispose(); + } + } + + /** + * This is a helper method for getTraceFrameData, to create for it a + * "best effort" GdbTraceEvent when a problem occurs during the reading. + * + * @param rank long containing the number of the frame where the problem occurred + * @param message String containing a brief explanation of problem. + * @return a GdbTraceEvent object, filled as best as possible + */ + private GdbTraceEvent createExceptionEvent(final long rank, final String message) { + // get corresponding TP data + String tmfEventRef; + String tmfEventSrc; + MIBreakpointDMData bp = fTpInfo.get(rank); + if (bp != null) { + tmfEventRef = bp.getFileName() + ":" + bp.getLineNumber() + " :: " + bp.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$ + tmfEventSrc = bp.getFileName() + " :: " + bp.getFunctionName() + ", line: " + bp.getLineNumber(); //$NON-NLS-1$ //$NON-NLS-2$ + } + else { + tmfEventRef = tracedExecutable; + tmfEventSrc = "Tracepoint: n/a"; //$NON-NLS-1$ + } + + GdbTraceEventContent evContent = new GdbTraceEventContent("ERROR: " + message, 0, 0); //$NON-NLS-1$ + + GdbTraceEvent ev = new GdbTraceEvent(fGdbTrace, + new TmfTimestamp(rank), + tmfEventSrc, + tmfEventType, + evContent, + tmfEventRef); + + return ev; + } + + /** + * @return DSF-GDB session id of the current session. + */ + public String getSessionId() { + return fSessionId; + } + + /** + * Handler method that catches the DSF "record selected changed" event. + * It in turn creates a TMF "time sync" signal. + * @param event TraceRecordSelectedChangedEvent: The DSF event. + */ + @DsfServiceEventHandler + public void handleDSFRecordSelectedEvents(final ITraceRecordSelectedChangedDMEvent event) { + if (event instanceof TraceRecordSelectedChangedEvent) { + TraceRecordSelectedChangedEvent traceEvent = (TraceRecordSelectedChangedEvent) event; + ITraceRecordDMContext context = traceEvent.getDMContext(); + final String reference = context.getRecordId(); + if (reference != null) { + int recordId = Integer.parseInt(reference); + selectGdbTraceEditor(context.getSessionId(), recordId); + } + } + } + + private static void closeGdbTraceEditor(final String sessionId) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (IWorkbenchWindow wbWindow : PlatformUI.getWorkbench().getWorkbenchWindows()) { + for (IWorkbenchPage wbPage : wbWindow.getPages()) { + for (IEditorReference editorReference : wbPage.getEditorReferences()) { + IEditorPart editor = editorReference.getEditor(false); + if (editor instanceof ITmfTraceEditor) { + ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace(); + if (trace instanceof GdbTrace) { + if (((GdbTrace) trace).getDsfSessionId().equals(sessionId)) { + wbPage.closeEditor(editor, false); + } + } + } + } + } + } + } + }); + } + + private static void selectGdbTraceEditor(final String sessionId, final int recordId) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (IWorkbenchWindow wbWindow : PlatformUI.getWorkbench().getWorkbenchWindows()) { + for (IWorkbenchPage wbPage : wbWindow.getPages()) { + for (IEditorReference editorReference : wbPage.getEditorReferences()) { + IEditorPart editor = editorReference.getEditor(false); + if (editor instanceof ITmfTraceEditor) { + ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace(); + if (trace instanceof GdbTrace) { + if (((GdbTrace) trace).getDsfSessionId().equals(sessionId)) { + wbPage.bringToTop(editor); + if (recordId != -1) { + gotoRank(editor, recordId); + } + return; + } + } else if (trace instanceof TmfExperiment) { + TmfExperiment experiment = (TmfExperiment) trace; + int nbTraces = experiment.getTraces().length; + for (int i = 0; i < nbTraces; i++) { + GdbTrace gdbTrace = (GdbTrace) experiment.getTraces()[i]; + if (gdbTrace.getDsfSessionId().equals(sessionId)) { + wbPage.bringToTop(editor); + if (recordId != -1) { + int rank = recordId * nbTraces + i; + gotoRank(editor, rank); + } + return; + } + } + } + } + } + } + } + } + }); + } + + private static void gotoRank(IEditorPart editor, int rank) { + IEditorInput editorInput = editor.getEditorInput(); + if (editorInput instanceof IFileEditorInput) { + IFile file = ((IFileEditorInput) editorInput).getFile(); + try { + final IMarker marker = file.createMarker(IMarker.MARKER); + marker.setAttribute(IMarker.LOCATION, (Integer) rank); + IDE.gotoMarker(editor, marker); + marker.delete(); + } catch (CoreException e) { + e.printStackTrace(); + } + } + } +}
\ No newline at end of file |