1 /*******************************************************************************
2 * Copyright (c) 2011, 2015 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Marc Dumais - Initial implementation
11 * Francois Chouinard - Misc improvements, DSF signal handling, dynamic experiment
12 * Patrick Tasse - Updated for TMF 2.0
13 * Bernd Hufmann - Fixed deadlock during shutdown
14 *******************************************************************************/
16 package org
.eclipse
.tracecompass
.internal
.gdbtrace
.core
.trace
;
18 import java
.util
.HashMap
;
19 import java
.util
.Hashtable
;
20 import java
.util
.List
;
22 import java
.util
.concurrent
.ExecutionException
;
23 import java
.util
.concurrent
.RejectedExecutionException
;
24 import java
.util
.concurrent
.TimeUnit
;
25 import java
.util
.concurrent
.TimeoutException
;
27 import org
.eclipse
.cdt
.dsf
.concurrent
.DataRequestMonitor
;
28 import org
.eclipse
.cdt
.dsf
.concurrent
.DsfExecutor
;
29 import org
.eclipse
.cdt
.dsf
.concurrent
.IDsfStatusConstants
;
30 import org
.eclipse
.cdt
.dsf
.concurrent
.Query
;
31 import org
.eclipse
.cdt
.dsf
.datamodel
.DMContexts
;
32 import org
.eclipse
.cdt
.dsf
.datamodel
.IDMContext
;
33 import org
.eclipse
.cdt
.dsf
.debug
.service
.IBreakpoints
;
34 import org
.eclipse
.cdt
.dsf
.debug
.service
.IBreakpoints
.IBreakpointsTargetDMContext
;
35 import org
.eclipse
.cdt
.dsf
.debug
.service
.IRunControl
.IContainerDMContext
;
36 import org
.eclipse
.cdt
.dsf
.debug
.service
.command
.ICommandControlService
;
37 import org
.eclipse
.cdt
.dsf
.debug
.service
.command
.ICommandControlService
.ICommandControlDMContext
;
38 import org
.eclipse
.cdt
.dsf
.gdb
.IGdbDebugPreferenceConstants
;
39 import org
.eclipse
.cdt
.dsf
.gdb
.internal
.GdbPlugin
;
40 import org
.eclipse
.cdt
.dsf
.gdb
.launching
.GdbLaunch
;
41 import org
.eclipse
.cdt
.dsf
.gdb
.service
.GDBTraceControl_7_2
.TraceRecordSelectedChangedEvent
;
42 import org
.eclipse
.cdt
.dsf
.gdb
.service
.IGDBTraceControl
;
43 import org
.eclipse
.cdt
.dsf
.gdb
.service
.IGDBTraceControl
.ITraceRecordDMContext
;
44 import org
.eclipse
.cdt
.dsf
.gdb
.service
.IGDBTraceControl
.ITraceRecordDMData
;
45 import org
.eclipse
.cdt
.dsf
.gdb
.service
.IGDBTraceControl
.ITraceRecordSelectedChangedDMEvent
;
46 import org
.eclipse
.cdt
.dsf
.gdb
.service
.IGDBTraceControl
.ITraceStatusDMData
;
47 import org
.eclipse
.cdt
.dsf
.gdb
.service
.IGDBTraceControl
.ITraceTargetDMContext
;
48 import org
.eclipse
.cdt
.dsf
.mi
.service
.IMICommandControl
;
49 import org
.eclipse
.cdt
.dsf
.mi
.service
.IMIProcesses
;
50 import org
.eclipse
.cdt
.dsf
.mi
.service
.MIBreakpointDMData
;
51 import org
.eclipse
.cdt
.dsf
.mi
.service
.MIBreakpoints
;
52 import org
.eclipse
.cdt
.dsf
.mi
.service
.command
.CommandFactory
;
53 import org
.eclipse
.cdt
.dsf
.mi
.service
.command
.output
.MIBreakListInfo
;
54 import org
.eclipse
.cdt
.dsf
.mi
.service
.command
.output
.MIBreakpoint
;
55 import org
.eclipse
.cdt
.dsf
.service
.DsfServiceEventHandler
;
56 import org
.eclipse
.cdt
.dsf
.service
.DsfServicesTracker
;
57 import org
.eclipse
.cdt
.dsf
.service
.DsfSession
;
58 import org
.eclipse
.core
.resources
.IFile
;
59 import org
.eclipse
.core
.resources
.IMarker
;
60 import org
.eclipse
.core
.runtime
.CoreException
;
61 import org
.eclipse
.core
.runtime
.IAdaptable
;
62 import org
.eclipse
.core
.runtime
.IPath
;
63 import org
.eclipse
.core
.runtime
.IStatus
;
64 import org
.eclipse
.core
.runtime
.Platform
;
65 import org
.eclipse
.core
.runtime
.Status
;
66 import org
.eclipse
.debug
.core
.DebugException
;
67 import org
.eclipse
.debug
.core
.DebugPlugin
;
68 import org
.eclipse
.debug
.core
.ILaunch
;
69 import org
.eclipse
.debug
.core
.ILaunchConfigurationType
;
70 import org
.eclipse
.debug
.core
.ILaunchConfigurationWorkingCopy
;
71 import org
.eclipse
.debug
.core
.ILaunchesListener2
;
72 import org
.eclipse
.debug
.internal
.ui
.viewers
.model
.provisional
.ITreeModelViewer
;
73 import org
.eclipse
.debug
.ui
.AbstractDebugView
;
74 import org
.eclipse
.debug
.ui
.DebugUITools
;
75 import org
.eclipse
.debug
.ui
.IDebugUIConstants
;
76 import org
.eclipse
.debug
.ui
.contexts
.DebugContextEvent
;
77 import org
.eclipse
.debug
.ui
.contexts
.IDebugContextListener
;
78 import org
.eclipse
.jface
.viewers
.ISelection
;
79 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
80 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
81 import org
.eclipse
.jface
.viewers
.Viewer
;
82 import org
.eclipse
.swt
.widgets
.Display
;
83 import org
.eclipse
.tracecompass
.internal
.gdbtrace
.core
.GdbTraceCorePlugin
;
84 import org
.eclipse
.tracecompass
.internal
.gdbtrace
.core
.event
.GdbTraceEvent
;
85 import org
.eclipse
.tracecompass
.internal
.gdbtrace
.core
.event
.GdbTraceEventContent
;
86 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventField
;
87 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventType
;
88 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
89 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
90 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.experiment
.TmfExperiment
;
91 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.ITmfTraceEditor
;
92 import org
.eclipse
.ui
.IEditorInput
;
93 import org
.eclipse
.ui
.IEditorPart
;
94 import org
.eclipse
.ui
.IEditorReference
;
95 import org
.eclipse
.ui
.IFileEditorInput
;
96 import org
.eclipse
.ui
.IViewPart
;
97 import org
.eclipse
.ui
.IWorkbench
;
98 import org
.eclipse
.ui
.IWorkbenchPage
;
99 import org
.eclipse
.ui
.IWorkbenchWindow
;
100 import org
.eclipse
.ui
.PlatformUI
;
101 import org
.eclipse
.ui
.ide
.IDE
;
104 * Adaptor to access GDB Tracepoint frames, previously collected and saved in a
105 * file by GDB. One instance of this maps to a single DSF-GDB session.
107 * This class offers the functions of starting a post-mortem GDB session with a
108 * tracepoint data file, navigate the data frames and return the data contained
109 * in a given tracepoint frame.
111 * Note: GDB 7.2 or later is required to handle tracepoints
113 * @author Marc Dumais
114 * @author Francois Chouinard
116 @SuppressWarnings("restriction")
117 public class DsfGdbAdaptor
{
119 private static final Object SESSION_LOCK
= new Object();
120 private static final String INTERRUPTION_EXCEPTION
= "Interruption exception"; //$NON-NLS-1$
121 private static final String GDB_EXCEPTION
= "GDB exception"; //$NON-NLS-1$
122 private static final String REQUEST_REJECTED_EXCEPTION
= "Request rejected exception"; //$NON-NLS-1$
123 private static final String TIMEOUT
= "Timeout"; //$NON-NLS-1$
125 private GdbTrace fGdbTrace
;
127 private int fNumberOfFrames
= 0;
128 private boolean fIsTimeoutEnabled
;
129 private int fTimeout
;
131 private ILaunch fLaunch
;
132 private boolean isTerminating
;
133 private DsfSession fDsfSession
= null;
134 private String fSessionId
;
136 private String tracedExecutable
= ""; //$NON-NLS-1$
138 private String gdb72Executable
= ""; //$NON-NLS-1$
139 private String fTraceFilePath
= ""; //$NON-NLS-1$
140 private String fTraceFile
= ""; //$NON-NLS-1$
141 private String sourceLocator
= ""; //$NON-NLS-1$
143 // To save tracepoints detailed info. The key is the rank of the
144 // breakpoint (tracepoint is a kind of breakpoint)
145 private Map
<Integer
, MIBreakpointDMData
> fTpInfo
= new HashMap
<>();
147 private TmfEventType tmfEventType
= new TmfEventType("GDB Tracepoint", TmfEventField
.makeRoot(new String
[] { "Content" })); //$NON-NLS-1$ //$NON-NLS-2$
150 new DsfGdbPlatformEventListener();
154 * <b><u>DsfGdbPlatformEventListener</u></b>
156 * Listens to platform and DSF-GDB events that announce important events
157 * about the launchers or a change in debug context that we might need to
160 * @author Francois Chouinard
162 private class DsfGdbPlatformEventListener
implements
163 ILaunchesListener2
, IDebugContextListener
{
168 public DsfGdbPlatformEventListener() {
169 Display
.getDefault().syncExec(new Runnable() {
172 DebugPlugin
.getDefault().getLaunchManager().addLaunchListener(DsfGdbPlatformEventListener
.this);
173 IWorkbench wb
= PlatformUI
.getWorkbench();
174 IWorkbenchWindow win
= wb
.getActiveWorkbenchWindow();
175 DebugUITools
.getDebugContextManager().getContextService(win
).addDebugContextListener(DsfGdbPlatformEventListener
.this);
181 public synchronized void launchesRemoved(ILaunch
[] launches
) {
185 public synchronized void launchesAdded(ILaunch
[] launches
) {
189 public synchronized void launchesChanged(ILaunch
[] launches
) {
193 public synchronized void launchesTerminated(ILaunch
[] launches
) {
194 for (ILaunch launch
: launches
) {
195 String sessionId
= ((GdbLaunch
) launch
).getSession().getId();
196 closeGdbTraceEditor(sessionId
);
200 private String fCurrentSessionId
= ""; //$NON-NLS-1$
202 public void debugContextChanged(DebugContextEvent event
) {
203 ISelection selection
= event
.getContext();
204 if (selection
instanceof IStructuredSelection
) {
205 List
<?
> eventContextList
= ((IStructuredSelection
) selection
).toList();
206 for (Object eventContext
: eventContextList
) {
207 if (eventContext
instanceof IAdaptable
) {
208 Object contextObject
= ((IAdaptable
) eventContext
).getAdapter(IDMContext
.class);
209 IDMContext context
= (IDMContext
) contextObject
;
210 if (context
!= null) {
212 synchronized(SESSION_LOCK
) {
213 sessionId
= context
.getSessionId();
214 if (sessionId
.equals(fCurrentSessionId
)) {
217 fCurrentSessionId
= sessionId
;
219 // Get the current trace record
220 final DsfExecutor executor
= DsfSession
.getSession(sessionId
).getExecutor();
221 final DsfServicesTracker tracker
= new DsfServicesTracker(GdbTraceCorePlugin
.getBundleContext(), sessionId
);
222 Query
<ITraceRecordDMContext
> getCurrentRecordQuery
= new Query
<ITraceRecordDMContext
>() {
224 public void execute(final DataRequestMonitor
<ITraceRecordDMContext
> queryRm
) {
225 final IGDBTraceControl traceControl
= tracker
.getService(IGDBTraceControl
.class);
226 final ICommandControlService commandControl
= tracker
.getService(ICommandControlService
.class);
227 if (traceControl
!= null && commandControl
!= null) {
228 ITraceTargetDMContext traceContext
= (ITraceTargetDMContext
) commandControl
.getContext();
229 traceControl
.getCurrentTraceRecordContext(traceContext
, queryRm
);
236 executor
.execute(getCurrentRecordQuery
);
237 ITraceRecordDMContext record
;
238 if (DsfGdbAdaptor
.this.fIsTimeoutEnabled
) {
239 record
= getCurrentRecordQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
);
241 record
= getCurrentRecordQuery
.get();
243 // If we get a trace record, it means that this can be used
244 if (record
!= null && record
.getRecordId() != null) {
245 int recordId
= Integer
.parseInt(record
.getRecordId());
246 selectGdbTraceEditor(sessionId
, recordId
);
249 } catch (InterruptedException e
) {
250 GdbTraceCorePlugin
.logError(INTERRUPTION_EXCEPTION
, e
);
251 } catch (ExecutionException e
) {
252 GdbTraceCorePlugin
.logError(GDB_EXCEPTION
, e
);
253 } catch (RejectedExecutionException e
) {
254 GdbTraceCorePlugin
.logError(REQUEST_REJECTED_EXCEPTION
, e
);
255 } catch (TimeoutException e
) {
256 GdbTraceCorePlugin
.logError(TIMEOUT
, e
);
260 // else not DSF-GDB or GDB < 7.2
267 } // class DsfGdbPlatformEventListener
270 * Constructor for DsfGdbAdaptor. This is used when we want to launch a
271 * DSF-GDB session and use it as source in our tracing perspective.
272 * i.e. when launching from the Project Explorer
274 * @param trace the GDB trace
275 * @param gdbExec GDB executable. Must be version 7.2 or later.
276 * @param traceFile previously generated GDB tracepoint file
277 * @param tracedExecutable executable that was used to generate the tracefile
278 * workspace, where the traced executable was taken from.
280 public DsfGdbAdaptor(GdbTrace trace
, String gdbExec
, String traceFile
, String tracedExecutable
) {
281 this.fGdbTrace
= trace
;
282 this.gdb72Executable
= gdbExec
;
283 this.fTraceFilePath
= traceFile
;
284 this.fTraceFile
= traceFile
.substring(traceFile
.lastIndexOf(IPath
.SEPARATOR
) + 1);
285 this.tracedExecutable
= tracedExecutable
;
288 launchDGBPostMortemTrace();
289 } catch (CoreException e
) {
295 * Builds a launcher and launches a Post-mortem GDB session, based on a
296 * previously-gathered GDB Tracepoint file. The information used to
297 * create the launcher is provided to the constructor of this class,
298 * at instantiation time.
300 * Note: Requires GDB 7.2 or later
302 private void launchDGBPostMortemTrace() throws CoreException
{
303 fIsTimeoutEnabled
= Platform
.getPreferencesService().getBoolean(GdbPlugin
.PLUGIN_ID
, IGdbDebugPreferenceConstants
.PREF_COMMAND_TIMEOUT
, false, null);
304 if (fIsTimeoutEnabled
) {
305 fTimeout
= Platform
.getPreferencesService().getInt(GdbPlugin
.PLUGIN_ID
, IGdbDebugPreferenceConstants
.PREF_COMMAND_TIMEOUT_VALUE
, IGdbDebugPreferenceConstants
.COMMAND_TIMEOUT_VALUE_DEFAULT
, null);
308 ILaunchConfigurationType configType
= DebugPlugin
311 .getLaunchConfigurationType("org.eclipse.cdt.launch.postmortemLaunchType"); //$NON-NLS-1$
312 ILaunchConfigurationWorkingCopy wc
= configType
.newInstance(null, fTraceFile
);
314 wc
.setAttribute("org.eclipse.cdt.dsf.gdb.DEBUG_NAME", gdb72Executable
); //$NON-NLS-1$
315 wc
.setAttribute("org.eclipse.cdt.dsf.gdb.POST_MORTEM_TYPE", "TRACE_FILE"); //$NON-NLS-1$ //$NON-NLS-2$
316 wc
.setAttribute("org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR", 0); //$NON-NLS-1$
317 wc
.setAttribute("org.eclipse.cdt.launch.COREFILE_PATH", fTraceFilePath
); //$NON-NLS-1$
318 wc
.setAttribute("org.eclipse.cdt.launch.DEBUGGER_START_MODE", "core"); //$NON-NLS-1$ //$NON-NLS-2$
319 wc
.setAttribute("org.eclipse.cdt.launch.PROGRAM_NAME", tracedExecutable
); //$NON-NLS-1$
320 // So that the GDB launch is synchronous
321 wc
.setAttribute("org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND", false); //$NON-NLS-1$
323 if (!sourceLocator
.isEmpty()) {
324 wc
.setAttribute("org.eclipse.debug.core.source_locator_memento", sourceLocator
); //$NON-NLS-1$
327 // Launch GDB session
328 fLaunch
= wc
.doSave().launch("debug", null); //$NON-NLS-1$
329 isTerminating
= false;
331 if (fLaunch
instanceof GdbLaunch
) {
332 fSessionId
= ((GdbLaunch
) fLaunch
).getSession().getId();
335 fDsfSession
= ((GdbLaunch
) fLaunch
).getSession();
336 fDsfSession
.addServiceEventListener(this, null);
338 // Find the number of frames contained in the tracepoint file
339 fNumberOfFrames
= findNumFrames();
343 * This method terminates the current DSF-GDB session
345 public void dispose() {
346 if (fLaunch
!= null && fLaunch
.canTerminate() && !isTerminating
) {
347 isTerminating
= true;
350 } catch (DebugException e
) {
358 * This method will try (once per call) to get the number of GDB tracepoint
359 * frames for the current session, from DSF-GDB, until it succeeds at
360 * getting an amount different than zero.
362 * @return The number of frames in current session or zero if unsuccessful
364 public int getNumberOfFrames() {
365 if (fNumberOfFrames
== 0) {
366 fNumberOfFrames
= findNumFrames();
368 return fNumberOfFrames
;
373 * Wrapper around the selecting of a frame and the reading of its
374 * information. this is a work-around for the potential problem of
375 * concurrent access to these functions by more than one thread,
376 * where two clients might interfere with each other.
378 * Note: We also try to get the tracepoint info here, if it's not
381 * @param rank a long corresponding to the number of the frame to be
383 * @return A GdbTraceEvent object, or null in case of failure.
385 public synchronized GdbTraceEvent
selectAndReadFrame(final long rank
) {
386 // lazy init of tracepoints info
387 if(fTpInfo
.isEmpty()) {
390 if (selectDataFrame(rank
, false)) {
391 GdbTraceEvent event
= getTraceFrameData(rank
);
392 long ts
= event
.getTimestamp().getValue();
402 * This class implements a best-effort look-up of the detailed tracepoint
403 * information (source code filename, line number, etc...).
405 private void getTracepointInfo() {
407 // Get the latest executor/service tracker
408 final DsfExecutor executor
= DsfSession
.getSession(fSessionId
).getExecutor();
409 final DsfServicesTracker tracker
= new DsfServicesTracker(GdbTraceCorePlugin
.getBundleContext(), fSessionId
);
411 Query
<Object
> selectRecordQuery
= new Query
<Object
>() {
413 public void execute(final DataRequestMonitor
<Object
> drm
) {
415 // A breakpoint is no longer GDB-global but tied to a specific process
416 // So we need to find our process and the ask for its breakpoints
417 IMIProcesses procService
= tracker
.getService(IMIProcesses
.class);
418 final ICommandControlService cmdControl
= tracker
.getService(ICommandControlService
.class);
419 if (procService
== null || cmdControl
== null) {
420 drm
.setStatus(new Status(IStatus
.ERROR
, GdbPlugin
.PLUGIN_ID
, IDsfStatusConstants
.INTERNAL_ERROR
, "Could not find necessary services", null)); //$NON-NLS-1$
425 ITraceTargetDMContext context
= (ITraceTargetDMContext
) cmdControl
.getContext();
426 ICommandControlDMContext cmdControlDMC
= DMContexts
.getAncestorOfType(context
, ICommandControlDMContext
.class);
428 procService
.getProcessesBeingDebugged(
430 new DataRequestMonitor
<IDMContext
[]>(executor
, drm
) {
432 protected void handleSuccess() {
433 assert getData() != null;
434 assert getData().length
== 1;
435 if (getData() == null || getData().length
< 1) {
440 // Choose the first process for now, until gdb can tell
441 // us which process the trace record is associated with.
442 IContainerDMContext containerDMC
= (IContainerDMContext
)(getData()[0]);
443 IBreakpointsTargetDMContext bpTargetDMC
= DMContexts
.getAncestorOfType(containerDMC
, IBreakpointsTargetDMContext
.class);
445 IMICommandControl commandService
= tracker
.getService(IMICommandControl
.class);
446 if (commandService
== null) {
447 drm
.setStatus(new Status(IStatus
.ERROR
, GdbPlugin
.PLUGIN_ID
, IDsfStatusConstants
.INTERNAL_ERROR
, "Could not find necessary services", null)); //$NON-NLS-1$
452 CommandFactory cmdFactory
= commandService
.getCommandFactory();
453 IBreakpoints bpService
= tracker
.getService(MIBreakpoints
.class);
454 if (cmdFactory
== null || bpService
== null) {
455 drm
.setStatus(new Status(IStatus
.ERROR
, GdbPlugin
.PLUGIN_ID
, IDsfStatusConstants
.INTERNAL_ERROR
, "Could not find necessary services", null)); //$NON-NLS-1$
460 // Execute the command
461 cmdControl
.queueCommand(cmdFactory
.createMIBreakList(bpTargetDMC
),
462 new DataRequestMonitor
<MIBreakListInfo
>(executor
, drm
) {
464 protected void handleSuccess() {
465 MIBreakpoint
[] breakpoints
= getData().getMIBreakpoints();
466 for (int i
= 0; i
< breakpoints
.length
; i
++) {
467 MIBreakpointDMData breakpoint
= new MIBreakpointDMData(breakpoints
[i
]);
468 String type
= breakpoint
.getBreakpointType();
469 // Only save info if the current breakpoint is of type tracepoint
470 if(type
.compareTo(MIBreakpoints
.TRACEPOINT
) == 0 ) {
471 fTpInfo
.put(Integer
.valueOf(breakpoint
.getReference()), breakpoint
);
482 executor
.execute(selectRecordQuery
);
483 if (fIsTimeoutEnabled
) {
484 selectRecordQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
); // blocks until time out
486 selectRecordQuery
.get(); // blocks
488 } catch (InterruptedException e
) {
489 GdbTraceCorePlugin
.logError(INTERRUPTION_EXCEPTION
, e
);
490 } catch (ExecutionException e
) {
491 GdbTraceCorePlugin
.logError(GDB_EXCEPTION
, e
);
492 } catch (RejectedExecutionException e
) {
493 GdbTraceCorePlugin
.logError(REQUEST_REJECTED_EXCEPTION
, e
);
494 } catch (TimeoutException e
) {
495 GdbTraceCorePlugin
.logError(TIMEOUT
, e
);
502 * Returns the number of frames contained in currently loaded tracepoint GDB
505 * Note: A postmortem GDB session must be started before calling
508 * @return the number of frames contained in currently loaded tracepoint GDB
509 * session or zero in case of error
511 private synchronized int findNumFrames() {
514 if (DsfSession
.getSession(fSessionId
) == null) {
518 final DsfExecutor executor
= DsfSession
.getSession(fSessionId
)
520 final DsfServicesTracker tracker
= new DsfServicesTracker(
521 GdbTraceCorePlugin
.getBundleContext(), fSessionId
);
523 Query
<ITraceStatusDMData
> selectRecordQuery
= new Query
<ITraceStatusDMData
>() {
526 final DataRequestMonitor
<ITraceStatusDMData
> queryRm
) {
527 final IGDBTraceControl traceControl
= tracker
528 .getService(IGDBTraceControl
.class);
530 final ICommandControlService commandControl
= tracker
.getService(ICommandControlService
.class);
531 if (commandControl
== null) {
532 queryRm
.setStatus(new Status(IStatus
.ERROR
, GdbPlugin
.PLUGIN_ID
, IDsfStatusConstants
.INTERNAL_ERROR
, "Could not find necessary services", null)); //$NON-NLS-1$
536 final ITraceTargetDMContext dmc
= (ITraceTargetDMContext
) commandControl
539 if (traceControl
!= null) {
540 traceControl
.getTraceStatus(dmc
, queryRm
);
547 executor
.execute(selectRecordQuery
);
548 ITraceStatusDMData data
;
549 if (fIsTimeoutEnabled
) {
550 data
= selectRecordQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
); // blocks until time out
552 data
= selectRecordQuery
.get(); // blocks
555 frameNum
= data
.getNumberOfCollectedFrame();
556 } catch (InterruptedException e
) {
557 GdbTraceCorePlugin
.logError(INTERRUPTION_EXCEPTION
, e
);
558 } catch (ExecutionException e
) {
559 GdbTraceCorePlugin
.logError(GDB_EXCEPTION
, e
);
560 } catch (RejectedExecutionException e
) {
561 GdbTraceCorePlugin
.logError(REQUEST_REJECTED_EXCEPTION
, e
);
562 } catch (TimeoutException e
) {
563 GdbTraceCorePlugin
.logError(TIMEOUT
, e
);
571 * This method uses the DSF-GDB interface to select a given frame number
572 * in the current GDB tracepoint session.
574 * @param rank the rank of the tracepoint frame to select.
575 * @param update true if visualization should be updated
576 * @return boolean true if select worked.
578 public boolean selectDataFrame(final long rank
, final boolean update
) {
579 boolean status
= true;
581 final DsfSession dsfSession
= DsfSession
.getSession(fSessionId
);
582 if (dsfSession
== null) {
588 * Clear the selection to ensure that the new selection is not
589 * prevented from overriding the current selection by the DSF
590 * selection policy. This could be removed when DSF provides
591 * an API to force the trace record selection in the Debug view.
593 Display
.getDefault().syncExec(new Runnable() {
596 for (IWorkbenchWindow wbWindow
: PlatformUI
.getWorkbench().getWorkbenchWindows()) {
597 for (IWorkbenchPage wbPage
: wbWindow
.getPages()) {
598 IViewPart vp
= wbPage
.findView(IDebugUIConstants
.ID_DEBUG_VIEW
);
599 if (vp
instanceof AbstractDebugView
) {
600 Viewer viewer
= ((AbstractDebugView
) vp
).getViewer();
601 if (viewer
instanceof ITreeModelViewer
) {
602 ((ITreeModelViewer
) viewer
).setSelection(StructuredSelection
.EMPTY
, false, true);
611 final DsfExecutor executor
= dsfSession
.getExecutor();
612 final DsfServicesTracker tracker
= new DsfServicesTracker(GdbTraceCorePlugin
.getBundleContext(), fSessionId
);
614 Query
<Object
> selectRecordQuery
= new Query
<Object
>() {
616 public void execute(final DataRequestMonitor
<Object
> queryRm
) {
617 final IGDBTraceControl traceControl
= tracker
.getService(IGDBTraceControl
.class);
619 final ICommandControlService commandControl
= tracker
.getService(ICommandControlService
.class);
620 if (commandControl
== null) {
621 queryRm
.setStatus(new Status(IStatus
.ERROR
, GdbPlugin
.PLUGIN_ID
, IDsfStatusConstants
.INTERNAL_ERROR
, "Could not find necessary services", null)); //$NON-NLS-1$
626 final ITraceTargetDMContext dmc
= (ITraceTargetDMContext
) commandControl
.getContext();
628 if (traceControl
!= null) {
629 ITraceRecordDMContext newCtx
= traceControl
.createTraceRecordContext(dmc
, Integer
.toString((int) rank
));
631 dsfSession
.dispatchEvent(new TraceRecordSelectedChangedEvent(newCtx
), new Hashtable
<String
, String
>());
633 traceControl
.selectTraceRecord(newCtx
, queryRm
);
640 executor
.execute(selectRecordQuery
);
641 if (fIsTimeoutEnabled
) {
642 selectRecordQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
); // blocks until time out
644 selectRecordQuery
.get(); // blocks
646 } catch (InterruptedException e
) {
648 GdbTraceCorePlugin
.logError(INTERRUPTION_EXCEPTION
, e
);
649 } catch (ExecutionException e
) {
651 GdbTraceCorePlugin
.logError(GDB_EXCEPTION
, e
);
652 } catch (RejectedExecutionException e
) {
654 GdbTraceCorePlugin
.logError(REQUEST_REJECTED_EXCEPTION
, e
);
655 } catch (TimeoutException e
) {
657 GdbTraceCorePlugin
.logError(TIMEOUT
, e
);
665 * This method uses DSF-GDB to read the currently selected GDB tracepoint
666 * data frame. An object of type GdbTraceEvent is build based on the
667 * information contained in the data frame and returned to the caller.
669 * NOTE : A frame must be selected before calling this method!
671 * @param rank for internal purposes - does <b>not</b> control which
672 * frame will be read!
673 * @return parsed tp frame, in the form of a GdbTraceEvent
675 private GdbTraceEvent
getTraceFrameData(final long rank
) {
677 if (DsfSession
.getSession(fSessionId
) == null) {
681 final DsfExecutor executor
= DsfSession
.getSession(fSessionId
).getExecutor();
682 final DsfServicesTracker tracker
= new DsfServicesTracker(GdbTraceCorePlugin
.getBundleContext(), fSessionId
);
684 Query
<ITraceRecordDMData
> getFrameDataQuery
= new Query
<ITraceRecordDMData
>() {
686 public void execute(final DataRequestMonitor
<ITraceRecordDMData
> rm
) {
687 final IGDBTraceControl traceControl
= tracker
.getService(IGDBTraceControl
.class);
689 final ICommandControlService commandControl
= tracker
.getService(ICommandControlService
.class);
690 if (commandControl
== null) {
691 rm
.setStatus(new Status(IStatus
.ERROR
, GdbPlugin
.PLUGIN_ID
, IDsfStatusConstants
.INTERNAL_ERROR
, "Could not find necessary services", null)); //$NON-NLS-1$
695 final ITraceTargetDMContext dmc
= (ITraceTargetDMContext
) commandControl
.getContext();
697 if (traceControl
!= null) {
698 traceControl
.getCurrentTraceRecordContext(dmc
,
699 new DataRequestMonitor
<ITraceRecordDMContext
>(executor
, rm
) {
701 protected void handleSuccess() {
702 traceControl
.getTraceRecordData(getData(), rm
);
711 // Execute the above query
712 executor
.execute(getFrameDataQuery
);
713 ITraceRecordDMData data
;
714 if (fIsTimeoutEnabled
) {
715 data
= getFrameDataQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
); // blocking call until time out
717 data
= getFrameDataQuery
.get();
724 String ts
= data
.getTimestamp();
726 ts
= "0"; //$NON-NLS-1$
729 // get corresponding TP data
731 MIBreakpointDMData bp
= fTpInfo
.get(Integer
.valueOf(data
.getTracepointNumber()));
733 tmfEventRef
= bp
.getFileName() + ":" + bp
.getLineNumber() + " :: " + bp
.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$
736 tmfEventRef
= tracedExecutable
;
739 GdbTraceEventContent evContent
= new GdbTraceEventContent(
741 Integer
.parseInt(data
.getTracepointNumber()),
742 Integer
.parseInt(data
.getRecordId()));
744 GdbTraceEvent ev
= new GdbTraceEvent(fGdbTrace
,
745 new TmfTimestamp(Integer
.parseInt(data
.getRecordId())),
746 "Tracepoint: " + data
.getTracepointNumber() + ", Frame: " + data
.getRecordId(), //$NON-NLS-1$ //$NON-NLS-2$
753 } catch (InterruptedException e
) {
754 return createExceptionEvent(rank
, INTERRUPTION_EXCEPTION
);
755 } catch (java
.util
.concurrent
.ExecutionException e
) {
756 return createExceptionEvent(rank
, GDB_EXCEPTION
);
757 } catch (RejectedExecutionException e
) {
758 return createExceptionEvent(rank
, REQUEST_REJECTED_EXCEPTION
);
759 } catch (TimeoutException e
) {
760 return createExceptionEvent(rank
, TIMEOUT
);
769 * This is a helper method for getTraceFrameData, to create for it a
770 * "best effort" GdbTraceEvent when a problem occurs during the reading.
772 * @param rank long containing the number of the frame where the problem occurred
773 * @param message String containing a brief explanation of problem.
774 * @return a GdbTraceEvent object, filled as best as possible
776 private GdbTraceEvent
createExceptionEvent(final long rank
, final String message
) {
777 // get corresponding TP data
780 MIBreakpointDMData bp
= fTpInfo
.get(rank
);
782 tmfEventRef
= bp
.getFileName() + ":" + bp
.getLineNumber() + " :: " + bp
.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$
783 tmfEventSrc
= bp
.getFileName() + " :: " + bp
.getFunctionName() + ", line: " + bp
.getLineNumber(); //$NON-NLS-1$ //$NON-NLS-2$
786 tmfEventRef
= tracedExecutable
;
787 tmfEventSrc
= "Tracepoint: n/a"; //$NON-NLS-1$
790 GdbTraceEventContent evContent
= new GdbTraceEventContent("ERROR: " + message
, 0, 0); //$NON-NLS-1$
792 GdbTraceEvent ev
= new GdbTraceEvent(fGdbTrace
,
793 new TmfTimestamp(rank
),
803 * @return DSF-GDB session id of the current session.
805 public String
getSessionId() {
810 * Handler method that catches the DSF "record selected changed" event.
811 * It in turn creates a TMF "time sync" signal.
812 * @param event TraceRecordSelectedChangedEvent: The DSF event.
814 @DsfServiceEventHandler
815 public void handleDSFRecordSelectedEvents(final ITraceRecordSelectedChangedDMEvent event
) {
816 if (event
instanceof TraceRecordSelectedChangedEvent
) {
817 TraceRecordSelectedChangedEvent traceEvent
= (TraceRecordSelectedChangedEvent
) event
;
818 ITraceRecordDMContext context
= traceEvent
.getDMContext();
819 final String reference
= context
.getRecordId();
820 if (reference
!= null) {
821 int recordId
= Integer
.parseInt(reference
);
822 selectGdbTraceEditor(context
.getSessionId(), recordId
);
827 private static void closeGdbTraceEditor(final String sessionId
) {
828 Display
.getDefault().asyncExec(new Runnable() {
831 for (IWorkbenchWindow wbWindow
: PlatformUI
.getWorkbench().getWorkbenchWindows()) {
832 for (IWorkbenchPage wbPage
: wbWindow
.getPages()) {
833 for (IEditorReference editorReference
: wbPage
.getEditorReferences()) {
834 IEditorPart editor
= editorReference
.getEditor(false);
835 if (editor
instanceof ITmfTraceEditor
) {
836 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
837 if (trace
instanceof GdbTrace
) {
838 if (((GdbTrace
) trace
).getDsfSessionId().equals(sessionId
)) {
839 wbPage
.closeEditor(editor
, false);
850 private static void selectGdbTraceEditor(final String sessionId
, final int recordId
) {
851 Display
.getDefault().asyncExec(new Runnable() {
854 for (IWorkbenchWindow wbWindow
: PlatformUI
.getWorkbench().getWorkbenchWindows()) {
855 for (IWorkbenchPage wbPage
: wbWindow
.getPages()) {
856 for (IEditorReference editorReference
: wbPage
.getEditorReferences()) {
857 IEditorPart editor
= editorReference
.getEditor(false);
858 if (editor
instanceof ITmfTraceEditor
) {
859 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
860 if (trace
instanceof GdbTrace
) {
861 if (((GdbTrace
) trace
).getDsfSessionId().equals(sessionId
)) {
862 wbPage
.bringToTop(editor
);
863 if (recordId
!= -1) {
864 gotoRank(editor
, recordId
);
868 } else if (trace
instanceof TmfExperiment
) {
869 TmfExperiment experiment
= (TmfExperiment
) trace
;
870 List
<ITmfTrace
> expTraces
= experiment
.getTraces();
871 int nbTraces
= expTraces
.size();
872 for (int i
= 0; i
< nbTraces
; i
++) {
873 GdbTrace gdbTrace
= (GdbTrace
) expTraces
.get(i
);
874 if (gdbTrace
.getDsfSessionId().equals(sessionId
)) {
875 wbPage
.bringToTop(editor
);
876 if (recordId
!= -1) {
877 int rank
= recordId
* nbTraces
+ i
;
878 gotoRank(editor
, rank
);
892 private static void gotoRank(IEditorPart editor
, int rank
) {
893 IEditorInput editorInput
= editor
.getEditorInput();
894 if (editorInput
instanceof IFileEditorInput
) {
895 IFile file
= ((IFileEditorInput
) editorInput
).getFile();
897 final IMarker marker
= file
.createMarker(IMarker
.MARKER
);
898 marker
.setAttribute(IMarker
.LOCATION
, (Integer
) rank
);
899 IDE
.gotoMarker(editor
, marker
);
901 } catch (CoreException e
) {