1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 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
.Activator
;
84 import org
.eclipse
.tracecompass
.internal
.gdbtrace
.core
.GdbTraceCorePlugin
;
85 import org
.eclipse
.tracecompass
.internal
.gdbtrace
.core
.event
.GdbTraceEvent
;
86 import org
.eclipse
.tracecompass
.internal
.gdbtrace
.core
.event
.GdbTraceEventContent
;
87 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventField
;
88 import org
.eclipse
.tracecompass
.tmf
.core
.event
.TmfEventType
;
89 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
90 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
91 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.experiment
.TmfExperiment
;
92 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.ITmfTraceEditor
;
93 import org
.eclipse
.ui
.IEditorInput
;
94 import org
.eclipse
.ui
.IEditorPart
;
95 import org
.eclipse
.ui
.IEditorReference
;
96 import org
.eclipse
.ui
.IFileEditorInput
;
97 import org
.eclipse
.ui
.IViewPart
;
98 import org
.eclipse
.ui
.IWorkbench
;
99 import org
.eclipse
.ui
.IWorkbenchPage
;
100 import org
.eclipse
.ui
.IWorkbenchWindow
;
101 import org
.eclipse
.ui
.PlatformUI
;
102 import org
.eclipse
.ui
.ide
.IDE
;
105 * Adaptor to access GDB Tracepoint frames, previously collected and saved in a
106 * file by GDB. One instance of this maps to a single DSF-GDB session.
108 * This class offers the functions of starting a post-mortem GDB session with a
109 * tracepoint data file, navigate the data frames and return the data contained
110 * in a given tracepoint frame.
112 * Note: GDB 7.2 or later is required to handle tracepoints
114 * @author Marc Dumais
115 * @author Francois Chouinard
117 @SuppressWarnings("restriction")
118 public class DsfGdbAdaptor
{
120 private GdbTrace fGdbTrace
;
122 private int fNumberOfFrames
= 0;
123 private boolean fIsTimeoutEnabled
;
124 private int fTimeout
;
126 private ILaunch fLaunch
;
127 private boolean isTerminating
;
128 private DsfSession fDsfSession
= null;
129 private String fSessionId
;
131 private String tracedExecutable
= ""; //$NON-NLS-1$
133 private String gdb72Executable
= ""; //$NON-NLS-1$
134 private String fTraceFilePath
= ""; //$NON-NLS-1$
135 private String fTraceFile
= ""; //$NON-NLS-1$
136 private String sourceLocator
= ""; //$NON-NLS-1$
138 // To save tracepoints detailed info. The key is the rank of the
139 // breakpoint (tracepoint is a kind of breakpoint)
140 private Map
<Integer
, MIBreakpointDMData
> fTpInfo
= new HashMap
<>();
142 private TmfEventType tmfEventType
= new TmfEventType("GDB Tracepoint", TmfEventField
.makeRoot(new String
[] { "Content" })); //$NON-NLS-1$ //$NON-NLS-2$
145 new DsfGdbPlatformEventListener();
149 * <b><u>DsfGdbPlatformEventListener</u></b>
151 * Listens to platform and DSF-GDB events that announce important events
152 * about the launchers or a change in debug context that we might need to
155 * @author Francois Chouinard
157 private class DsfGdbPlatformEventListener
implements
158 ILaunchesListener2
, IDebugContextListener
{
163 public DsfGdbPlatformEventListener() {
164 Display
.getDefault().syncExec(new Runnable() {
167 DebugPlugin
.getDefault().getLaunchManager().addLaunchListener(DsfGdbPlatformEventListener
.this);
168 IWorkbench wb
= PlatformUI
.getWorkbench();
169 IWorkbenchWindow win
= wb
.getActiveWorkbenchWindow();
170 DebugUITools
.getDebugContextManager().getContextService(win
).addDebugContextListener(DsfGdbPlatformEventListener
.this);
176 public synchronized void launchesRemoved(ILaunch
[] launches
) {
180 public synchronized void launchesAdded(ILaunch
[] launches
) {
184 public synchronized void launchesChanged(ILaunch
[] launches
) {
188 public synchronized void launchesTerminated(ILaunch
[] launches
) {
189 for (ILaunch launch
: launches
) {
190 String sessionId
= ((GdbLaunch
) launch
).getSession().getId();
191 closeGdbTraceEditor(sessionId
);
195 private String fCurrentSessionId
= ""; //$NON-NLS-1$
197 public void debugContextChanged(DebugContextEvent event
) {
198 ISelection selection
= event
.getContext();
199 if (selection
instanceof IStructuredSelection
) {
200 List
<?
> eventContextList
= ((IStructuredSelection
) selection
).toList();
201 for (Object eventContext
: eventContextList
) {
202 if (eventContext
instanceof IAdaptable
) {
203 IDMContext context
= (IDMContext
) ((IAdaptable
) eventContext
).getAdapter(IDMContext
.class);
204 if (context
!= null) {
206 synchronized(fCurrentSessionId
) {
207 sessionId
= context
.getSessionId();
208 if (sessionId
.equals(fCurrentSessionId
)) {
212 fCurrentSessionId
= sessionId
;
213 // Get the current trace record
214 final DsfExecutor executor
= DsfSession
.getSession(sessionId
).getExecutor();
215 final DsfServicesTracker tracker
= new DsfServicesTracker(GdbTraceCorePlugin
.getBundleContext(), sessionId
);
216 Query
<ITraceRecordDMContext
> getCurrentRecordQuery
= new Query
<ITraceRecordDMContext
>() {
218 public void execute(final DataRequestMonitor
<ITraceRecordDMContext
> queryRm
) {
219 final IGDBTraceControl traceControl
= tracker
.getService(IGDBTraceControl
.class);
220 final ICommandControlService commandControl
= tracker
.getService(ICommandControlService
.class);
221 if (traceControl
!= null && commandControl
!= null) {
222 ITraceTargetDMContext traceContext
= (ITraceTargetDMContext
) commandControl
.getContext();
223 traceControl
.getCurrentTraceRecordContext(traceContext
, queryRm
);
230 executor
.execute(getCurrentRecordQuery
);
231 ITraceRecordDMContext record
;
232 if (DsfGdbAdaptor
.this.fIsTimeoutEnabled
) {
233 record
= getCurrentRecordQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
);
235 record
= getCurrentRecordQuery
.get();
237 // If we get a trace record, it means that this can be used
238 if (record
!= null && record
.getRecordId() != null) {
239 int recordId
= Integer
.parseInt(record
.getRecordId());
240 selectGdbTraceEditor(sessionId
, recordId
);
243 } catch (InterruptedException e
) {
244 Activator
.logError("Interruption exception", e
); //$NON-NLS-1$
245 } catch (ExecutionException e
) {
246 Activator
.logError("GDB exception", e
); //$NON-NLS-1$
247 } catch (RejectedExecutionException e
) {
248 Activator
.logError("Request rejected exception", e
); //$NON-NLS-1$
249 } catch (TimeoutException e
) {
250 Activator
.logError("Timeout", e
); //$NON-NLS-1$
254 // else not DSF-GDB or GDB < 7.2
261 } // class DsfGdbPlatformEventListener
264 * Constructor for DsfGdbAdaptor. This is used when we want to launch a
265 * DSF-GDB session and use it as source in our tracing perspective.
266 * i.e. when launching from the Project Explorer
268 * @param trace the GDB trace
269 * @param gdbExec GDB executable. Must be version 7.2 or later.
270 * @param traceFile previously generated GDB tracepoint file
271 * @param tracedExecutable executable that was used to generate the tracefile
272 * workspace, where the traced executable was taken from.
274 public DsfGdbAdaptor(GdbTrace trace
, String gdbExec
, String traceFile
, String tracedExecutable
) {
275 this.fGdbTrace
= trace
;
276 this.gdb72Executable
= gdbExec
;
277 this.fTraceFilePath
= traceFile
;
278 this.fTraceFile
= traceFile
.substring(traceFile
.lastIndexOf(IPath
.SEPARATOR
) + 1);
279 this.tracedExecutable
= tracedExecutable
;
282 launchDGBPostMortemTrace();
283 } catch (CoreException e
) {
289 * Builds a launcher and launches a Post-mortem GDB session, based on a
290 * previously-gathered GDB Tracepoint file. The information used to
291 * create the launcher is provided to the constructor of this class,
292 * at instantiation time.
294 * Note: Requires GDB 7.2 or later
296 private void launchDGBPostMortemTrace() throws CoreException
{
297 fIsTimeoutEnabled
= Platform
.getPreferencesService().getBoolean(GdbPlugin
.PLUGIN_ID
, IGdbDebugPreferenceConstants
.PREF_COMMAND_TIMEOUT
, false, null);
298 if (fIsTimeoutEnabled
) {
299 fTimeout
= Platform
.getPreferencesService().getInt(GdbPlugin
.PLUGIN_ID
, IGdbDebugPreferenceConstants
.PREF_COMMAND_TIMEOUT_VALUE
, IGdbDebugPreferenceConstants
.COMMAND_TIMEOUT_VALUE_DEFAULT
, null);
302 ILaunchConfigurationType configType
= DebugPlugin
305 .getLaunchConfigurationType("org.eclipse.cdt.launch.postmortemLaunchType"); //$NON-NLS-1$
306 ILaunchConfigurationWorkingCopy wc
= configType
.newInstance(null, fTraceFile
);
308 wc
.setAttribute("org.eclipse.cdt.dsf.gdb.DEBUG_NAME", gdb72Executable
); //$NON-NLS-1$
309 wc
.setAttribute("org.eclipse.cdt.dsf.gdb.POST_MORTEM_TYPE", "TRACE_FILE"); //$NON-NLS-1$ //$NON-NLS-2$
310 wc
.setAttribute("org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR", 0); //$NON-NLS-1$
311 wc
.setAttribute("org.eclipse.cdt.launch.COREFILE_PATH", fTraceFilePath
); //$NON-NLS-1$
312 wc
.setAttribute("org.eclipse.cdt.launch.DEBUGGER_START_MODE", "core"); //$NON-NLS-1$ //$NON-NLS-2$
313 wc
.setAttribute("org.eclipse.cdt.launch.PROGRAM_NAME", tracedExecutable
); //$NON-NLS-1$
314 // So that the GDB launch is synchronous
315 wc
.setAttribute("org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND", false); //$NON-NLS-1$
317 if (!sourceLocator
.isEmpty()) {
318 wc
.setAttribute("org.eclipse.debug.core.source_locator_memento", sourceLocator
); //$NON-NLS-1$
321 // Launch GDB session
322 fLaunch
= wc
.doSave().launch("debug", null); //$NON-NLS-1$
323 isTerminating
= false;
325 if (fLaunch
instanceof GdbLaunch
) {
326 fSessionId
= ((GdbLaunch
) fLaunch
).getSession().getId();
329 fDsfSession
= ((GdbLaunch
) fLaunch
).getSession();
330 fDsfSession
.addServiceEventListener(this, null);
332 // Find the number of frames contained in the tracepoint file
333 fNumberOfFrames
= findNumFrames();
337 * This method terminates the current DSF-GDB session
339 public void dispose() {
340 if (fLaunch
!= null && fLaunch
.canTerminate() && !isTerminating
) {
341 isTerminating
= true;
344 } catch (DebugException e
) {
352 * This method will try (once per call) to get the number of GDB tracepoint
353 * frames for the current session, from DSF-GDB, until it succeeds at
354 * getting an amount different than zero.
356 * @return The number of frames in current session or zero if unsuccessful
358 public int getNumberOfFrames() {
359 if (fNumberOfFrames
== 0) {
360 fNumberOfFrames
= findNumFrames();
362 return fNumberOfFrames
;
367 * Wrapper around the selecting of a frame and the reading of its
368 * information. this is a work-around for the potential problem of
369 * concurrent access to these functions by more than one thread,
370 * where two clients might interfere with each other.
372 * Note: We also try to get the tracepoint info here, if it's not
375 * @param rank a long corresponding to the number of the frame to be
377 * @return A GdbTraceEvent object, or null in case of failure.
379 public synchronized GdbTraceEvent
selectAndReadFrame(final long rank
) {
380 // lazy init of tracepoints info
381 if(fTpInfo
.isEmpty()) {
384 if (selectDataFrame(rank
, false)) {
385 GdbTraceEvent event
= getTraceFrameData(rank
);
386 long ts
= event
.getTimestamp().getValue();
396 * This class implements a best-effort look-up of the detailed tracepoint
397 * information (source code filename, line number, etc...).
399 private void getTracepointInfo() {
401 // Get the latest executor/service tracker
402 final DsfExecutor executor
= DsfSession
.getSession(fSessionId
).getExecutor();
403 final DsfServicesTracker tracker
= new DsfServicesTracker(GdbTraceCorePlugin
.getBundleContext(), fSessionId
);
405 Query
<Object
> selectRecordQuery
= new Query
<Object
>() {
407 public void execute(final DataRequestMonitor
<Object
> drm
) {
409 // A breakpoint is no longer GDB-global but tied to a specific process
410 // So we need to find our process and the ask for its breakpoints
411 IMIProcesses procService
= tracker
.getService(IMIProcesses
.class);
412 final ICommandControlService cmdControl
= tracker
.getService(ICommandControlService
.class);
413 if (procService
== null || cmdControl
== null) {
414 drm
.setStatus(new Status(IStatus
.ERROR
, GdbPlugin
.PLUGIN_ID
, IDsfStatusConstants
.INTERNAL_ERROR
, "Could not find necessary services", null)); //$NON-NLS-1$
419 ITraceTargetDMContext context
= (ITraceTargetDMContext
) cmdControl
.getContext();
420 ICommandControlDMContext cmdControlDMC
= DMContexts
.getAncestorOfType(context
, ICommandControlDMContext
.class);
422 procService
.getProcessesBeingDebugged(
424 new DataRequestMonitor
<IDMContext
[]>(executor
, drm
) {
426 protected void handleSuccess() {
427 assert getData() != null;
428 assert getData().length
== 1;
429 if (getData() == null || getData().length
< 1) {
434 // Choose the first process for now, until gdb can tell
435 // us which process the trace record is associated with.
436 IContainerDMContext containerDMC
= (IContainerDMContext
)(getData()[0]);
437 IBreakpointsTargetDMContext bpTargetDMC
= DMContexts
.getAncestorOfType(containerDMC
, IBreakpointsTargetDMContext
.class);
439 CommandFactory cmdFactory
= tracker
.getService(IMICommandControl
.class).getCommandFactory();
440 IBreakpoints bpService
= tracker
.getService(MIBreakpoints
.class);
441 if (cmdFactory
== null || bpService
== null) {
442 drm
.setStatus(new Status(IStatus
.ERROR
, GdbPlugin
.PLUGIN_ID
, IDsfStatusConstants
.INTERNAL_ERROR
, "Could not find necessary services", null)); //$NON-NLS-1$
447 // Execute the command
448 cmdControl
.queueCommand(cmdFactory
.createMIBreakList(bpTargetDMC
),
449 new DataRequestMonitor
<MIBreakListInfo
>(executor
, drm
) {
451 protected void handleSuccess() {
452 MIBreakpoint
[] breakpoints
= getData().getMIBreakpoints();
453 for (int i
= 0; i
< breakpoints
.length
; i
++) {
454 MIBreakpointDMData breakpoint
= new MIBreakpointDMData(breakpoints
[i
]);
455 String type
= breakpoint
.getBreakpointType();
456 // Only save info if the current breakpoint is of type tracepoint
457 if(type
.compareTo(MIBreakpoints
.TRACEPOINT
) == 0 ) {
458 fTpInfo
.put(new Integer(breakpoint
.getReference()), breakpoint
);
469 executor
.execute(selectRecordQuery
);
470 if (fIsTimeoutEnabled
) {
471 selectRecordQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
); // blocks until time out
473 selectRecordQuery
.get(); // blocks
475 } catch (InterruptedException e
) {
476 Activator
.logError("Interruption exception", e
); //$NON-NLS-1$
477 } catch (ExecutionException e
) {
478 Activator
.logError("GDB exception", e
); //$NON-NLS-1$
479 } catch (RejectedExecutionException e
) {
480 Activator
.logError("Request rejected exception", e
); //$NON-NLS-1$
481 } catch (TimeoutException e
) {
482 Activator
.logError("Timeout", e
); //$NON-NLS-1$
489 * Returns the number of frames contained in currently loaded tracepoint GDB
492 * Note: A postmortem GDB session must be started before calling
495 * @return the number of frames contained in currently loaded tracepoint GDB
496 * session or zero in case of error
498 private synchronized int findNumFrames() {
501 if (DsfSession
.getSession(fSessionId
) == null) {
505 final DsfExecutor executor
= DsfSession
.getSession(fSessionId
)
507 final DsfServicesTracker tracker
= new DsfServicesTracker(
508 GdbTraceCorePlugin
.getBundleContext(), fSessionId
);
510 Query
<ITraceStatusDMData
> selectRecordQuery
= new Query
<ITraceStatusDMData
>() {
513 final DataRequestMonitor
<ITraceStatusDMData
> queryRm
) {
514 final IGDBTraceControl traceControl
= tracker
515 .getService(IGDBTraceControl
.class);
517 final ICommandControlService commandControl
= tracker
518 .getService(ICommandControlService
.class);
519 final ITraceTargetDMContext dmc
= (ITraceTargetDMContext
) commandControl
522 if (traceControl
!= null) {
523 traceControl
.getTraceStatus(dmc
, queryRm
);
530 executor
.execute(selectRecordQuery
);
531 ITraceStatusDMData data
;
532 if (fIsTimeoutEnabled
) {
533 data
= selectRecordQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
); // blocks until time out
535 data
= selectRecordQuery
.get(); // blocks
538 frameNum
= data
.getNumberOfCollectedFrame();
539 } catch (InterruptedException e
) {
540 Activator
.logError("Interruption exception", e
); //$NON-NLS-1$
541 } catch (ExecutionException e
) {
542 Activator
.logError("GDB exception", e
); //$NON-NLS-1$
543 } catch (RejectedExecutionException e
) {
544 Activator
.logError("Request rejected exception", e
); //$NON-NLS-1$
545 } catch (TimeoutException e
) {
546 Activator
.logError("Timeout", e
); //$NON-NLS-1$
554 * This method uses the DSF-GDB interface to select a given frame number
555 * in the current GDB tracepoint session.
557 * @param rank the rank of the tracepoint frame to select.
558 * @param update true if visualization should be updated
559 * @return boolean true if select worked.
561 public boolean selectDataFrame(final long rank
, final boolean update
) {
562 boolean status
= true;
564 final DsfSession dsfSession
= DsfSession
.getSession(fSessionId
);
565 if (dsfSession
== null) {
571 * Clear the selection to ensure that the new selection is not
572 * prevented from overriding the current selection by the DSF
573 * selection policy. This could be removed when DSF provides
574 * an API to force the trace record selection in the Debug view.
576 Display
.getDefault().syncExec(new Runnable() {
579 for (IWorkbenchWindow wbWindow
: PlatformUI
.getWorkbench().getWorkbenchWindows()) {
580 for (IWorkbenchPage wbPage
: wbWindow
.getPages()) {
581 IViewPart vp
= wbPage
.findView(IDebugUIConstants
.ID_DEBUG_VIEW
);
582 if (vp
instanceof AbstractDebugView
) {
583 Viewer viewer
= ((AbstractDebugView
) vp
).getViewer();
584 if (viewer
instanceof ITreeModelViewer
) {
585 ((ITreeModelViewer
) viewer
).setSelection(StructuredSelection
.EMPTY
, false, true);
594 final DsfExecutor executor
= dsfSession
.getExecutor();
595 final DsfServicesTracker tracker
= new DsfServicesTracker(GdbTraceCorePlugin
.getBundleContext(), fSessionId
);
597 Query
<Object
> selectRecordQuery
= new Query
<Object
>() {
599 public void execute(final DataRequestMonitor
<Object
> queryRm
) {
600 final IGDBTraceControl traceControl
= tracker
.getService(IGDBTraceControl
.class);
602 final ICommandControlService commandControl
= tracker
.getService(ICommandControlService
.class);
603 final ITraceTargetDMContext dmc
= (ITraceTargetDMContext
) commandControl
.getContext();
605 if (traceControl
!= null) {
606 ITraceRecordDMContext newCtx
= traceControl
.createTraceRecordContext(dmc
, Integer
.toString((int) rank
));
608 dsfSession
.dispatchEvent(new TraceRecordSelectedChangedEvent(newCtx
), new Hashtable
<String
, String
>());
610 traceControl
.selectTraceRecord(newCtx
, queryRm
);
617 executor
.execute(selectRecordQuery
);
618 if (fIsTimeoutEnabled
) {
619 selectRecordQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
); // blocks until time out
621 selectRecordQuery
.get(); // blocks
623 } catch (InterruptedException e
) {
625 Activator
.logError("Interruption exception", e
); //$NON-NLS-1$
626 } catch (ExecutionException e
) {
628 Activator
.logError("GDB exception", e
); //$NON-NLS-1$
629 } catch (RejectedExecutionException e
) {
631 Activator
.logError("Request rejected exception", e
); //$NON-NLS-1$
632 } catch (TimeoutException e
) {
634 Activator
.logError("Timeout", e
); //$NON-NLS-1$
642 * This method uses DSF-GDB to read the currently selected GDB tracepoint
643 * data frame. An object of type GdbTraceEvent is build based on the
644 * information contained in the data frame and returned to the caller.
646 * NOTE : A frame must be selected before calling this method!
648 * @param rank for internal purposes - does <b>not</b> control which
649 * frame will be read!
650 * @return parsed tp frame, in the form of a GdbTraceEvent
652 private GdbTraceEvent
getTraceFrameData(final long rank
) {
654 if (DsfSession
.getSession(fSessionId
) == null) {
658 final DsfExecutor executor
= DsfSession
.getSession(fSessionId
).getExecutor();
659 final DsfServicesTracker tracker
= new DsfServicesTracker(GdbTraceCorePlugin
.getBundleContext(), fSessionId
);
661 Query
<ITraceRecordDMData
> getFrameDataQuery
= new Query
<ITraceRecordDMData
>() {
663 public void execute(final DataRequestMonitor
<ITraceRecordDMData
> rm
) {
664 final IGDBTraceControl traceControl
= tracker
.getService(IGDBTraceControl
.class);
666 final ICommandControlService commandControl
= tracker
.getService(ICommandControlService
.class);
667 final ITraceTargetDMContext dmc
= (ITraceTargetDMContext
) commandControl
.getContext();
669 if (traceControl
!= null) {
670 traceControl
.getCurrentTraceRecordContext(dmc
,
671 new DataRequestMonitor
<ITraceRecordDMContext
>(executor
, rm
) {
673 protected void handleSuccess() {
674 traceControl
.getTraceRecordData(getData(), rm
);
683 // Execute the above query
684 executor
.execute(getFrameDataQuery
);
685 ITraceRecordDMData data
;
686 if (fIsTimeoutEnabled
) {
687 data
= getFrameDataQuery
.get(fTimeout
, TimeUnit
.MILLISECONDS
); // blocking call until time out
689 data
= getFrameDataQuery
.get();
696 String ts
= data
.getTimestamp();
698 ts
= "0"; //$NON-NLS-1$
701 // get corresponding TP data
703 MIBreakpointDMData bp
= fTpInfo
.get(Integer
.valueOf(data
.getTracepointNumber()));
705 tmfEventRef
= bp
.getFileName() + ":" + bp
.getLineNumber() + " :: " + bp
.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$
708 tmfEventRef
= tracedExecutable
;
711 GdbTraceEventContent evContent
= new GdbTraceEventContent(
713 Integer
.parseInt(data
.getTracepointNumber()),
714 Integer
.parseInt(data
.getRecordId()));
716 GdbTraceEvent ev
= new GdbTraceEvent(fGdbTrace
,
717 new TmfTimestamp(Integer
.parseInt(data
.getRecordId())),
718 "Tracepoint: " + data
.getTracepointNumber() + ", Frame: " + data
.getRecordId(), //$NON-NLS-1$ //$NON-NLS-2$
725 } catch (InterruptedException e
) {
726 return createExceptionEvent(rank
, "Interruption exception"); //$NON-NLS-1$
727 } catch (java
.util
.concurrent
.ExecutionException e
) {
728 return createExceptionEvent(rank
, "GDB exception"); //$NON-NLS-1$
729 } catch (RejectedExecutionException e
) {
730 return createExceptionEvent(rank
, "Request rejected exception"); //$NON-NLS-1$
731 } catch (TimeoutException e
) {
732 return createExceptionEvent(rank
, "Timeout"); //$NON-NLS-1$
741 * This is a helper method for getTraceFrameData, to create for it a
742 * "best effort" GdbTraceEvent when a problem occurs during the reading.
744 * @param rank long containing the number of the frame where the problem occurred
745 * @param message String containing a brief explanation of problem.
746 * @return a GdbTraceEvent object, filled as best as possible
748 private GdbTraceEvent
createExceptionEvent(final long rank
, final String message
) {
749 // get corresponding TP data
752 MIBreakpointDMData bp
= fTpInfo
.get(rank
);
754 tmfEventRef
= bp
.getFileName() + ":" + bp
.getLineNumber() + " :: " + bp
.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$
755 tmfEventSrc
= bp
.getFileName() + " :: " + bp
.getFunctionName() + ", line: " + bp
.getLineNumber(); //$NON-NLS-1$ //$NON-NLS-2$
758 tmfEventRef
= tracedExecutable
;
759 tmfEventSrc
= "Tracepoint: n/a"; //$NON-NLS-1$
762 GdbTraceEventContent evContent
= new GdbTraceEventContent("ERROR: " + message
, 0, 0); //$NON-NLS-1$
764 GdbTraceEvent ev
= new GdbTraceEvent(fGdbTrace
,
765 new TmfTimestamp(rank
),
775 * @return DSF-GDB session id of the current session.
777 public String
getSessionId() {
782 * Handler method that catches the DSF "record selected changed" event.
783 * It in turn creates a TMF "time sync" signal.
784 * @param event TraceRecordSelectedChangedEvent: The DSF event.
786 @DsfServiceEventHandler
787 public void handleDSFRecordSelectedEvents(final ITraceRecordSelectedChangedDMEvent event
) {
788 if (event
instanceof TraceRecordSelectedChangedEvent
) {
789 TraceRecordSelectedChangedEvent traceEvent
= (TraceRecordSelectedChangedEvent
) event
;
790 ITraceRecordDMContext context
= traceEvent
.getDMContext();
791 final String reference
= context
.getRecordId();
792 if (reference
!= null) {
793 int recordId
= Integer
.parseInt(reference
);
794 selectGdbTraceEditor(context
.getSessionId(), recordId
);
799 private static void closeGdbTraceEditor(final String sessionId
) {
800 Display
.getDefault().asyncExec(new Runnable() {
803 for (IWorkbenchWindow wbWindow
: PlatformUI
.getWorkbench().getWorkbenchWindows()) {
804 for (IWorkbenchPage wbPage
: wbWindow
.getPages()) {
805 for (IEditorReference editorReference
: wbPage
.getEditorReferences()) {
806 IEditorPart editor
= editorReference
.getEditor(false);
807 if (editor
instanceof ITmfTraceEditor
) {
808 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
809 if (trace
instanceof GdbTrace
) {
810 if (((GdbTrace
) trace
).getDsfSessionId().equals(sessionId
)) {
811 wbPage
.closeEditor(editor
, false);
822 private static void selectGdbTraceEditor(final String sessionId
, final int recordId
) {
823 Display
.getDefault().asyncExec(new Runnable() {
826 for (IWorkbenchWindow wbWindow
: PlatformUI
.getWorkbench().getWorkbenchWindows()) {
827 for (IWorkbenchPage wbPage
: wbWindow
.getPages()) {
828 for (IEditorReference editorReference
: wbPage
.getEditorReferences()) {
829 IEditorPart editor
= editorReference
.getEditor(false);
830 if (editor
instanceof ITmfTraceEditor
) {
831 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
832 if (trace
instanceof GdbTrace
) {
833 if (((GdbTrace
) trace
).getDsfSessionId().equals(sessionId
)) {
834 wbPage
.bringToTop(editor
);
835 if (recordId
!= -1) {
836 gotoRank(editor
, recordId
);
840 } else if (trace
instanceof TmfExperiment
) {
841 TmfExperiment experiment
= (TmfExperiment
) trace
;
842 int nbTraces
= experiment
.getTraces().length
;
843 for (int i
= 0; i
< nbTraces
; i
++) {
844 GdbTrace gdbTrace
= (GdbTrace
) experiment
.getTraces()[i
];
845 if (gdbTrace
.getDsfSessionId().equals(sessionId
)) {
846 wbPage
.bringToTop(editor
);
847 if (recordId
!= -1) {
848 int rank
= recordId
* nbTraces
+ i
;
849 gotoRank(editor
, rank
);
863 private static void gotoRank(IEditorPart editor
, int rank
) {
864 IEditorInput editorInput
= editor
.getEditorInput();
865 if (editorInput
instanceof IFileEditorInput
) {
866 IFile file
= ((IFileEditorInput
) editorInput
).getFile();
868 final IMarker marker
= file
.createMarker(IMarker
.MARKER
);
869 marker
.setAttribute(IMarker
.LOCATION
, (Integer
) rank
);
870 IDE
.gotoMarker(editor
, marker
);
872 } catch (CoreException e
) {