tmf: Move TmfExperiment to its own package
[deliverable/tracecompass.git] / org.eclipse.tracecompass.gdbtrace.core / src / org / eclipse / tracecompass / internal / gdbtrace / core / trace / DsfGdbAdaptor.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 Ericsson
3 *
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
8 *
9 * Contributors:
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 *******************************************************************************/
15
16 package org.eclipse.tracecompass.internal.gdbtrace.core.trace;
17
18 import java.util.HashMap;
19 import java.util.Hashtable;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.concurrent.ExecutionException;
23 import java.util.concurrent.RejectedExecutionException;
24 import java.util.concurrent.TimeUnit;
25 import java.util.concurrent.TimeoutException;
26
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;
103
104 /**
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.
107 * <p>
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.
111 * <p>
112 * Note: GDB 7.2 or later is required to handle tracepoints
113 *
114 * @author Marc Dumais
115 * @author Francois Chouinard
116 */
117 @SuppressWarnings("restriction")
118 public class DsfGdbAdaptor {
119
120 private GdbTrace fGdbTrace;
121
122 private int fNumberOfFrames = 0;
123 private boolean fIsTimeoutEnabled;
124 private int fTimeout;
125
126 private ILaunch fLaunch;
127 private boolean isTerminating;
128 private DsfSession fDsfSession = null;
129 private String fSessionId;
130
131 private String tracedExecutable = ""; //$NON-NLS-1$
132
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$
137
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<>();
141
142 private TmfEventType tmfEventType = new TmfEventType("GDB Tracepoint", TmfEventField.makeRoot(new String[] { "Content" })); //$NON-NLS-1$ //$NON-NLS-2$
143
144 {
145 new DsfGdbPlatformEventListener();
146 }
147
148 /**
149 * <b><u>DsfGdbPlatformEventListener</u></b>
150 * <p>
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
153 * react-to.
154 * <p>
155 * @author Francois Chouinard
156 */
157 private class DsfGdbPlatformEventListener implements
158 ILaunchesListener2, IDebugContextListener {
159
160 /**
161 *
162 */
163 public DsfGdbPlatformEventListener() {
164 Display.getDefault().syncExec(new Runnable() {
165 @Override
166 public void run() {
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);
171 }
172 });
173 }
174
175 @Override
176 public synchronized void launchesRemoved(ILaunch[] launches) {
177 }
178
179 @Override
180 public synchronized void launchesAdded(ILaunch[] launches) {
181 }
182
183 @Override
184 public synchronized void launchesChanged(ILaunch[] launches) {
185 }
186
187 @Override
188 public synchronized void launchesTerminated(ILaunch[] launches) {
189 for (ILaunch launch : launches) {
190 String sessionId = ((GdbLaunch) launch).getSession().getId();
191 closeGdbTraceEditor(sessionId);
192 }
193 }
194
195 private String fCurrentSessionId = ""; //$NON-NLS-1$
196 @Override
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) {
205 String sessionId;
206 synchronized(fCurrentSessionId) {
207 sessionId = context.getSessionId();
208 if (sessionId.equals(fCurrentSessionId)) {
209 return;
210 }
211 }
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>() {
217 @Override
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);
224 } else {
225 queryRm.done();
226 }
227 }
228 };
229 try {
230 executor.execute(getCurrentRecordQuery);
231 ITraceRecordDMContext record;
232 if (DsfGdbAdaptor.this.fIsTimeoutEnabled) {
233 record = getCurrentRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS);
234 } else {
235 record = getCurrentRecordQuery.get();
236 }
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);
241 break;
242 }
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$
251 } finally {
252 tracker.dispose();
253 }
254 // else not DSF-GDB or GDB < 7.2
255 }
256 }
257 // else not DSF
258 }
259 }
260 }
261 } // class DsfGdbPlatformEventListener
262
263 /**
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
267 *
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.
273 */
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;
280
281 try {
282 launchDGBPostMortemTrace();
283 } catch (CoreException e) {
284 e.printStackTrace();
285 }
286 }
287
288 /**
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.
293 * <p>
294 * Note: Requires GDB 7.2 or later
295 */
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);
300 }
301
302 ILaunchConfigurationType configType = DebugPlugin
303 .getDefault()
304 .getLaunchManager()
305 .getLaunchConfigurationType("org.eclipse.cdt.launch.postmortemLaunchType"); //$NON-NLS-1$
306 ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, fTraceFile);
307
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$
316
317 if (!sourceLocator.isEmpty()) {
318 wc.setAttribute("org.eclipse.debug.core.source_locator_memento", sourceLocator); //$NON-NLS-1$
319 }
320
321 // Launch GDB session
322 fLaunch = wc.doSave().launch("debug", null); //$NON-NLS-1$
323 isTerminating = false;
324
325 if (fLaunch instanceof GdbLaunch) {
326 fSessionId = ((GdbLaunch) fLaunch).getSession().getId();
327 }
328
329 fDsfSession = ((GdbLaunch) fLaunch).getSession();
330 fDsfSession.addServiceEventListener(this, null);
331
332 // Find the number of frames contained in the tracepoint file
333 fNumberOfFrames = findNumFrames();
334 }
335
336 /**
337 * This method terminates the current DSF-GDB session
338 */
339 public void dispose() {
340 if (fLaunch != null && fLaunch.canTerminate() && !isTerminating) {
341 isTerminating = true;
342 try {
343 fLaunch.terminate();
344 } catch (DebugException e) {
345 e.printStackTrace();
346 }
347 fLaunch = null;
348 }
349 }
350
351 /**
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.
355 *
356 * @return The number of frames in current session or zero if unsuccessful
357 */
358 public int getNumberOfFrames() {
359 if (fNumberOfFrames == 0) {
360 fNumberOfFrames = findNumFrames();
361 }
362 return fNumberOfFrames;
363 }
364
365
366 /**
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.
371 * <p>
372 * Note: We also try to get the tracepoint info here, if it's not
373 * already filled-in.
374 *
375 * @param rank a long corresponding to the number of the frame to be
376 * selected and read
377 * @return A GdbTraceEvent object, or null in case of failure.
378 */
379 public synchronized GdbTraceEvent selectAndReadFrame(final long rank) {
380 // lazy init of tracepoints info
381 if(fTpInfo.isEmpty()) {
382 getTracepointInfo();
383 }
384 if (selectDataFrame(rank, false)) {
385 GdbTraceEvent event = getTraceFrameData(rank);
386 long ts = event.getTimestamp().getValue();
387 if (ts == rank) {
388 return event;
389 }
390 }
391 return null;
392 }
393
394
395 /**
396 * This class implements a best-effort look-up of the detailed tracepoint
397 * information (source code filename, line number, etc...).
398 */
399 private void getTracepointInfo() {
400
401 // Get the latest executor/service tracker
402 final DsfExecutor executor = DsfSession.getSession(fSessionId).getExecutor();
403 final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId);
404
405 Query<Object> selectRecordQuery = new Query<Object>() {
406 @Override
407 public void execute(final DataRequestMonitor<Object> drm) {
408
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$
415 drm.done();
416 return;
417 }
418
419 ITraceTargetDMContext context = (ITraceTargetDMContext) cmdControl.getContext();
420 ICommandControlDMContext cmdControlDMC = DMContexts.getAncestorOfType(context, ICommandControlDMContext.class);
421
422 procService.getProcessesBeingDebugged(
423 cmdControlDMC,
424 new DataRequestMonitor<IDMContext[]>(executor, drm) {
425 @Override
426 protected void handleSuccess() {
427 assert getData() != null;
428 assert getData().length == 1;
429 if (getData() == null || getData().length < 1) {
430 drm.done();
431 return;
432 }
433
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);
438
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$
443 drm.done();
444 return;
445 }
446
447 // Execute the command
448 cmdControl.queueCommand(cmdFactory.createMIBreakList(bpTargetDMC),
449 new DataRequestMonitor<MIBreakListInfo>(executor, drm) {
450 @Override
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);
459 }
460 }
461 drm.done();
462 }
463 });
464 }
465 });
466 }
467 };
468 try {
469 executor.execute(selectRecordQuery);
470 if (fIsTimeoutEnabled) {
471 selectRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocks until time out
472 } else {
473 selectRecordQuery.get(); // blocks
474 }
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$
483 } finally {
484 tracker.dispose();
485 }
486 }
487
488 /**
489 * Returns the number of frames contained in currently loaded tracepoint GDB
490 * session.
491 * <p>
492 * Note: A postmortem GDB session must be started before calling
493 * this method
494 *
495 * @return the number of frames contained in currently loaded tracepoint GDB
496 * session or zero in case of error
497 */
498 private synchronized int findNumFrames() {
499 int frameNum = 0;
500
501 if (DsfSession.getSession(fSessionId) == null) {
502 return 0;
503 }
504
505 final DsfExecutor executor = DsfSession.getSession(fSessionId)
506 .getExecutor();
507 final DsfServicesTracker tracker = new DsfServicesTracker(
508 GdbTraceCorePlugin.getBundleContext(), fSessionId);
509
510 Query<ITraceStatusDMData> selectRecordQuery = new Query<ITraceStatusDMData>() {
511 @Override
512 public void execute(
513 final DataRequestMonitor<ITraceStatusDMData> queryRm) {
514 final IGDBTraceControl traceControl = tracker
515 .getService(IGDBTraceControl.class);
516
517 final ICommandControlService commandControl = tracker
518 .getService(ICommandControlService.class);
519 final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl
520 .getContext();
521
522 if (traceControl != null) {
523 traceControl.getTraceStatus(dmc, queryRm);
524 } else {
525 queryRm.done();
526 }
527 }
528 };
529 try {
530 executor.execute(selectRecordQuery);
531 ITraceStatusDMData data;
532 if (fIsTimeoutEnabled) {
533 data = selectRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocks until time out
534 } else {
535 data = selectRecordQuery.get(); // blocks
536 }
537
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$
547 } finally {
548 tracker.dispose();
549 }
550 return frameNum;
551 }
552
553 /**
554 * This method uses the DSF-GDB interface to select a given frame number
555 * in the current GDB tracepoint session.
556 *
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.
560 */
561 public boolean selectDataFrame(final long rank, final boolean update) {
562 boolean status = true;
563
564 final DsfSession dsfSession = DsfSession.getSession(fSessionId);
565 if (dsfSession == null) {
566 return false;
567 }
568
569 if (update) {
570 /*
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.
575 */
576 Display.getDefault().syncExec(new Runnable() {
577 @Override
578 public void run() {
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);
586 }
587 }
588 }
589 }
590 }
591 });
592 }
593
594 final DsfExecutor executor = dsfSession.getExecutor();
595 final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId);
596
597 Query<Object> selectRecordQuery = new Query<Object>() {
598 @Override
599 public void execute(final DataRequestMonitor<Object> queryRm) {
600 final IGDBTraceControl traceControl = tracker.getService(IGDBTraceControl.class);
601
602 final ICommandControlService commandControl = tracker.getService(ICommandControlService.class);
603 final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl.getContext();
604
605 if (traceControl != null) {
606 ITraceRecordDMContext newCtx = traceControl.createTraceRecordContext(dmc, Integer.toString((int) rank));
607 if (update) {
608 dsfSession.dispatchEvent(new TraceRecordSelectedChangedEvent(newCtx), new Hashtable<String, String>());
609 }
610 traceControl.selectTraceRecord(newCtx, queryRm);
611 } else {
612 queryRm.done();
613 }
614 }
615 };
616 try {
617 executor.execute(selectRecordQuery);
618 if (fIsTimeoutEnabled) {
619 selectRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocks until time out
620 } else {
621 selectRecordQuery.get(); // blocks
622 }
623 } catch (InterruptedException e) {
624 status = false;
625 Activator.logError("Interruption exception", e); //$NON-NLS-1$
626 } catch (ExecutionException e) {
627 status = false;
628 Activator.logError("GDB exception", e); //$NON-NLS-1$
629 } catch (RejectedExecutionException e) {
630 status = false;
631 Activator.logError("Request rejected exception", e); //$NON-NLS-1$
632 } catch (TimeoutException e) {
633 status = false;
634 Activator.logError("Timeout", e); //$NON-NLS-1$
635 } finally {
636 tracker.dispose();
637 }
638 return status;
639 }
640
641 /**
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.
645 * <p>
646 * NOTE : A frame must be selected before calling this method!
647 *
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
651 */
652 private GdbTraceEvent getTraceFrameData(final long rank) {
653
654 if (DsfSession.getSession(fSessionId) == null) {
655 return null;
656 }
657
658 final DsfExecutor executor = DsfSession.getSession(fSessionId).getExecutor();
659 final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId);
660
661 Query<ITraceRecordDMData> getFrameDataQuery = new Query<ITraceRecordDMData>() {
662 @Override
663 public void execute(final DataRequestMonitor<ITraceRecordDMData> rm) {
664 final IGDBTraceControl traceControl = tracker.getService(IGDBTraceControl.class);
665
666 final ICommandControlService commandControl = tracker.getService(ICommandControlService.class);
667 final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl.getContext();
668
669 if (traceControl != null) {
670 traceControl.getCurrentTraceRecordContext(dmc,
671 new DataRequestMonitor<ITraceRecordDMContext>(executor, rm) {
672 @Override
673 protected void handleSuccess() {
674 traceControl.getTraceRecordData(getData(), rm);
675 }
676 });
677 } else {
678 rm.done();
679 }
680 }
681 };
682 try {
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
688 } else {
689 data = getFrameDataQuery.get();
690 }
691
692 if (data == null) {
693 return null;
694 }
695
696 String ts = data.getTimestamp();
697 if (ts == null) {
698 ts = "0"; //$NON-NLS-1$
699 }
700
701 // get corresponding TP data
702 String tmfEventRef;
703 MIBreakpointDMData bp = fTpInfo.get(Integer.valueOf(data.getTracepointNumber()));
704 if (bp != null) {
705 tmfEventRef = bp.getFileName() + ":" + bp.getLineNumber() + " :: " + bp.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$
706 }
707 else {
708 tmfEventRef = tracedExecutable;
709 }
710
711 GdbTraceEventContent evContent = new GdbTraceEventContent(
712 data.getContent(),
713 Integer.parseInt(data.getTracepointNumber()),
714 Integer.parseInt(data.getRecordId()));
715
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$
719 tmfEventType,
720 evContent,
721 tmfEventRef);
722
723 return ev;
724
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$
733 }
734
735 finally {
736 tracker.dispose();
737 }
738 }
739
740 /**
741 * This is a helper method for getTraceFrameData, to create for it a
742 * "best effort" GdbTraceEvent when a problem occurs during the reading.
743 *
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
747 */
748 private GdbTraceEvent createExceptionEvent(final long rank, final String message) {
749 // get corresponding TP data
750 String tmfEventRef;
751 String tmfEventSrc;
752 MIBreakpointDMData bp = fTpInfo.get(rank);
753 if (bp != null) {
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$
756 }
757 else {
758 tmfEventRef = tracedExecutable;
759 tmfEventSrc = "Tracepoint: n/a"; //$NON-NLS-1$
760 }
761
762 GdbTraceEventContent evContent = new GdbTraceEventContent("ERROR: " + message, 0, 0); //$NON-NLS-1$
763
764 GdbTraceEvent ev = new GdbTraceEvent(fGdbTrace,
765 new TmfTimestamp(rank),
766 tmfEventSrc,
767 tmfEventType,
768 evContent,
769 tmfEventRef);
770
771 return ev;
772 }
773
774 /**
775 * @return DSF-GDB session id of the current session.
776 */
777 public String getSessionId() {
778 return fSessionId;
779 }
780
781 /**
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.
785 */
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);
795 }
796 }
797 }
798
799 private static void closeGdbTraceEditor(final String sessionId) {
800 Display.getDefault().asyncExec(new Runnable() {
801 @Override
802 public void run() {
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);
812 }
813 }
814 }
815 }
816 }
817 }
818 }
819 });
820 }
821
822 private static void selectGdbTraceEditor(final String sessionId, final int recordId) {
823 Display.getDefault().asyncExec(new Runnable() {
824 @Override
825 public void run() {
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);
837 }
838 return;
839 }
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);
850 }
851 return;
852 }
853 }
854 }
855 }
856 }
857 }
858 }
859 }
860 });
861 }
862
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();
867 try {
868 final IMarker marker = file.createMarker(IMarker.MARKER);
869 marker.setAttribute(IMarker.LOCATION, (Integer) rank);
870 IDE.gotoMarker(editor, marker);
871 marker.delete();
872 } catch (CoreException e) {
873 e.printStackTrace();
874 }
875 }
876 }
877 }
This page took 0.057522 seconds and 5 git commands to generate.