gdbtrace: Move plugins to the Trace Compass namespace
[deliverable/tracecompass.git] / org.eclipse.tracecompass.gdbtrace.core / src / org / eclipse / linuxtools / 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.linuxtools.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.linuxtools.internal.gdbtrace.core.Activator;
83 import org.eclipse.linuxtools.internal.gdbtrace.core.GdbTraceCorePlugin;
84 import org.eclipse.linuxtools.internal.gdbtrace.core.event.GdbTraceEvent;
85 import org.eclipse.linuxtools.internal.gdbtrace.core.event.GdbTraceEventContent;
86 import org.eclipse.linuxtools.tmf.core.event.ITmfEventType;
87 import org.eclipse.linuxtools.tmf.core.event.TmfEventField;
88 import org.eclipse.linuxtools.tmf.core.event.TmfEventType;
89 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
90 import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
91 import org.eclipse.linuxtools.tmf.core.trace.TmfExperiment;
92 import org.eclipse.linuxtools.tmf.ui.editors.ITmfTraceEditor;
93 import org.eclipse.swt.widgets.Display;
94 import org.eclipse.ui.IEditorInput;
95 import org.eclipse.ui.IEditorPart;
96 import org.eclipse.ui.IEditorReference;
97 import org.eclipse.ui.IFileEditorInput;
98 import org.eclipse.ui.IViewPart;
99 import org.eclipse.ui.IWorkbench;
100 import org.eclipse.ui.IWorkbenchPage;
101 import org.eclipse.ui.IWorkbenchWindow;
102 import org.eclipse.ui.PlatformUI;
103 import org.eclipse.ui.ide.IDE;
104
105 /**
106 * Adaptor to access GDB Tracepoint frames, previously collected and saved in a
107 * file by GDB. One instance of this maps to a single DSF-GDB session.
108 * <p>
109 * This class offers the functions of starting a post-mortem GDB session with a
110 * tracepoint data file, navigate the data frames and return the data contained
111 * in a given tracepoint frame.
112 * <p>
113 * Note: GDB 7.2 or later is required to handle tracepoints
114 *
115 * @author Marc Dumais
116 * @author Francois Chouinard
117 */
118 @SuppressWarnings("restriction")
119 public class DsfGdbAdaptor {
120
121 private GdbTrace fGdbTrace;
122
123 private int fNumberOfFrames = 0;
124 private boolean fIsTimeoutEnabled;
125 private int fTimeout;
126
127 private ILaunch fLaunch;
128 private boolean isTerminating;
129 private DsfSession fDsfSession = null;
130 private String fSessionId;
131
132 private String tracedExecutable = ""; //$NON-NLS-1$
133
134 private String gdb72Executable = ""; //$NON-NLS-1$
135 private String fTraceFilePath = ""; //$NON-NLS-1$
136 private String fTraceFile = ""; //$NON-NLS-1$
137 private String sourceLocator = ""; //$NON-NLS-1$
138
139 // To save tracepoints detailed info. The key is the rank of the
140 // breakpoint (tracepoint is a kind of breakpoint)
141 private Map<Integer, MIBreakpointDMData> fTpInfo = new HashMap<>();
142
143 private TmfEventType tmfEventType = new TmfEventType(ITmfEventType.DEFAULT_CONTEXT_ID, "GDB Tracepoint", TmfEventField.makeRoot(new String[] { "Content" })); //$NON-NLS-1$ //$NON-NLS-2$
144
145 {
146 new DsfGdbPlatformEventListener();
147 }
148
149 /**
150 * <b><u>DsfGdbPlatformEventListener</u></b>
151 * <p>
152 * Listens to platform and DSF-GDB events that announce important events
153 * about the launchers or a change in debug context that we might need to
154 * react-to.
155 * <p>
156 * @author Francois Chouinard
157 */
158 private class DsfGdbPlatformEventListener implements
159 ILaunchesListener2, IDebugContextListener {
160
161 /**
162 *
163 */
164 public DsfGdbPlatformEventListener() {
165 Display.getDefault().syncExec(new Runnable() {
166 @Override
167 public void run() {
168 DebugPlugin.getDefault().getLaunchManager().addLaunchListener(DsfGdbPlatformEventListener.this);
169 IWorkbench wb = PlatformUI.getWorkbench();
170 IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
171 DebugUITools.getDebugContextManager().getContextService(win).addDebugContextListener(DsfGdbPlatformEventListener.this);
172 }
173 });
174 }
175
176 @Override
177 public synchronized void launchesRemoved(ILaunch[] launches) {
178 }
179
180 @Override
181 public synchronized void launchesAdded(ILaunch[] launches) {
182 }
183
184 @Override
185 public synchronized void launchesChanged(ILaunch[] launches) {
186 }
187
188 @Override
189 public synchronized void launchesTerminated(ILaunch[] launches) {
190 for (ILaunch launch : launches) {
191 String sessionId = ((GdbLaunch) launch).getSession().getId();
192 closeGdbTraceEditor(sessionId);
193 }
194 }
195
196 private String fCurrentSessionId = ""; //$NON-NLS-1$
197 @Override
198 public void debugContextChanged(DebugContextEvent event) {
199 ISelection selection = event.getContext();
200 if (selection instanceof IStructuredSelection) {
201 List<?> eventContextList = ((IStructuredSelection) selection).toList();
202 for (Object eventContext : eventContextList) {
203 if (eventContext instanceof IAdaptable) {
204 IDMContext context = (IDMContext) ((IAdaptable) eventContext).getAdapter(IDMContext.class);
205 if (context != null) {
206 String sessionId;
207 synchronized(fCurrentSessionId) {
208 sessionId = context.getSessionId();
209 if (sessionId.equals(fCurrentSessionId)) {
210 return;
211 }
212 }
213 fCurrentSessionId = sessionId;
214 // Get the current trace record
215 final DsfExecutor executor = DsfSession.getSession(sessionId).getExecutor();
216 final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), sessionId);
217 Query<ITraceRecordDMContext> getCurrentRecordQuery = new Query<ITraceRecordDMContext>() {
218 @Override
219 public void execute(final DataRequestMonitor<ITraceRecordDMContext> queryRm) {
220 final IGDBTraceControl traceControl = tracker.getService(IGDBTraceControl.class);
221 final ICommandControlService commandControl = tracker.getService(ICommandControlService.class);
222 if (traceControl != null && commandControl != null) {
223 ITraceTargetDMContext traceContext = (ITraceTargetDMContext) commandControl.getContext();
224 traceControl.getCurrentTraceRecordContext(traceContext, queryRm);
225 } else {
226 queryRm.done();
227 }
228 }
229 };
230 try {
231 executor.execute(getCurrentRecordQuery);
232 ITraceRecordDMContext record;
233 if (DsfGdbAdaptor.this.fIsTimeoutEnabled) {
234 record = getCurrentRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS);
235 } else {
236 record = getCurrentRecordQuery.get();
237 }
238 // If we get a trace record, it means that this can be used
239 if (record != null && record.getRecordId() != null) {
240 int recordId = Integer.parseInt(record.getRecordId());
241 selectGdbTraceEditor(sessionId, recordId);
242 break;
243 }
244 } catch (InterruptedException e) {
245 Activator.logError("Interruption exception", e); //$NON-NLS-1$
246 } catch (ExecutionException e) {
247 Activator.logError("GDB exception", e); //$NON-NLS-1$
248 } catch (RejectedExecutionException e) {
249 Activator.logError("Request rejected exception", e); //$NON-NLS-1$
250 } catch (TimeoutException e) {
251 Activator.logError("Timeout", e); //$NON-NLS-1$
252 } finally {
253 tracker.dispose();
254 }
255 // else not DSF-GDB or GDB < 7.2
256 }
257 }
258 // else not DSF
259 }
260 }
261 }
262 } // class DsfGdbPlatformEventListener
263
264 /**
265 * Constructor for DsfGdbAdaptor. This is used when we want to launch a
266 * DSF-GDB session and use it as source in our tracing perspective.
267 * i.e. when launching from the Project Explorer
268 *
269 * @param trace the GDB trace
270 * @param gdbExec GDB executable. Must be version 7.2 or later.
271 * @param traceFile previously generated GDB tracepoint file
272 * @param tracedExecutable executable that was used to generate the tracefile
273 * workspace, where the traced executable was taken from.
274 */
275 public DsfGdbAdaptor(GdbTrace trace, String gdbExec, String traceFile, String tracedExecutable) {
276 this.fGdbTrace = trace;
277 this.gdb72Executable = gdbExec;
278 this.fTraceFilePath = traceFile;
279 this.fTraceFile = traceFile.substring(traceFile.lastIndexOf(IPath.SEPARATOR) + 1);
280 this.tracedExecutable = tracedExecutable;
281
282 try {
283 launchDGBPostMortemTrace();
284 } catch (CoreException e) {
285 e.printStackTrace();
286 }
287 }
288
289 /**
290 * Builds a launcher and launches a Post-mortem GDB session, based on a
291 * previously-gathered GDB Tracepoint file. The information used to
292 * create the launcher is provided to the constructor of this class,
293 * at instantiation time.
294 * <p>
295 * Note: Requires GDB 7.2 or later
296 */
297 private void launchDGBPostMortemTrace() throws CoreException {
298 fIsTimeoutEnabled = Platform.getPreferencesService().getBoolean(GdbPlugin.PLUGIN_ID, IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT, false, null);
299 if (fIsTimeoutEnabled) {
300 fTimeout = Platform.getPreferencesService().getInt(GdbPlugin.PLUGIN_ID, IGdbDebugPreferenceConstants.PREF_COMMAND_TIMEOUT_VALUE, IGdbDebugPreferenceConstants.COMMAND_TIMEOUT_VALUE_DEFAULT, null);
301 }
302
303 ILaunchConfigurationType configType = DebugPlugin
304 .getDefault()
305 .getLaunchManager()
306 .getLaunchConfigurationType("org.eclipse.cdt.launch.postmortemLaunchType"); //$NON-NLS-1$
307 ILaunchConfigurationWorkingCopy wc = configType.newInstance(null, fTraceFile);
308
309 wc.setAttribute("org.eclipse.cdt.dsf.gdb.DEBUG_NAME", gdb72Executable); //$NON-NLS-1$
310 wc.setAttribute("org.eclipse.cdt.dsf.gdb.POST_MORTEM_TYPE", "TRACE_FILE"); //$NON-NLS-1$ //$NON-NLS-2$
311 wc.setAttribute("org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR", 0); //$NON-NLS-1$
312 wc.setAttribute("org.eclipse.cdt.launch.COREFILE_PATH", fTraceFilePath); //$NON-NLS-1$
313 wc.setAttribute("org.eclipse.cdt.launch.DEBUGGER_START_MODE", "core"); //$NON-NLS-1$ //$NON-NLS-2$
314 wc.setAttribute("org.eclipse.cdt.launch.PROGRAM_NAME", tracedExecutable); //$NON-NLS-1$
315 // So that the GDB launch is synchronous
316 wc.setAttribute("org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND", false); //$NON-NLS-1$
317
318 if (!sourceLocator.isEmpty()) {
319 wc.setAttribute("org.eclipse.debug.core.source_locator_memento", sourceLocator); //$NON-NLS-1$
320 }
321
322 // Launch GDB session
323 fLaunch = wc.doSave().launch("debug", null); //$NON-NLS-1$
324 isTerminating = false;
325
326 if (fLaunch instanceof GdbLaunch) {
327 fSessionId = ((GdbLaunch) fLaunch).getSession().getId();
328 }
329
330 fDsfSession = ((GdbLaunch) fLaunch).getSession();
331 fDsfSession.addServiceEventListener(this, null);
332
333 // Find the number of frames contained in the tracepoint file
334 fNumberOfFrames = findNumFrames();
335 }
336
337 /**
338 * This method terminates the current DSF-GDB session
339 */
340 public void dispose() {
341 if (fLaunch != null && fLaunch.canTerminate() && !isTerminating) {
342 isTerminating = true;
343 try {
344 fLaunch.terminate();
345 } catch (DebugException e) {
346 e.printStackTrace();
347 }
348 fLaunch = null;
349 }
350 }
351
352 /**
353 * This method will try (once per call) to get the number of GDB tracepoint
354 * frames for the current session, from DSF-GDB, until it succeeds at
355 * getting an amount different than zero.
356 *
357 * @return The number of frames in current session or zero if unsuccessful
358 */
359 public int getNumberOfFrames() {
360 if (fNumberOfFrames == 0) {
361 fNumberOfFrames = findNumFrames();
362 }
363 return fNumberOfFrames;
364 }
365
366
367 /**
368 * Wrapper around the selecting of a frame and the reading of its
369 * information. this is a work-around for the potential problem of
370 * concurrent access to these functions by more than one thread,
371 * where two clients might interfere with each other.
372 * <p>
373 * Note: We also try to get the tracepoint info here, if it's not
374 * already filled-in.
375 *
376 * @param rank a long corresponding to the number of the frame to be
377 * selected and read
378 * @return A GdbTraceEvent object, or null in case of failure.
379 */
380 public synchronized GdbTraceEvent selectAndReadFrame(final long rank) {
381 // lazy init of tracepoints info
382 if(fTpInfo.isEmpty()) {
383 getTracepointInfo();
384 }
385 if (selectDataFrame(rank, false)) {
386 GdbTraceEvent event = getTraceFrameData(rank);
387 long ts = event.getTimestamp().getValue();
388 if (ts == rank) {
389 return event;
390 }
391 }
392 return null;
393 }
394
395
396 /**
397 * This class implements a best-effort look-up of the detailed tracepoint
398 * information (source code filename, line number, etc...).
399 */
400 private void getTracepointInfo() {
401
402 // Get the latest executor/service tracker
403 final DsfExecutor executor = DsfSession.getSession(fSessionId).getExecutor();
404 final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId);
405
406 Query<Object> selectRecordQuery = new Query<Object>() {
407 @Override
408 public void execute(final DataRequestMonitor<Object> drm) {
409
410 // A breakpoint is no longer GDB-global but tied to a specific process
411 // So we need to find our process and the ask for its breakpoints
412 IMIProcesses procService = tracker.getService(IMIProcesses.class);
413 final ICommandControlService cmdControl = tracker.getService(ICommandControlService.class);
414 if (procService == null || cmdControl == null) {
415 drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Could not find necessary services", null)); //$NON-NLS-1$
416 drm.done();
417 return;
418 }
419
420 ITraceTargetDMContext context = (ITraceTargetDMContext) cmdControl.getContext();
421 ICommandControlDMContext cmdControlDMC = DMContexts.getAncestorOfType(context, ICommandControlDMContext.class);
422
423 procService.getProcessesBeingDebugged(
424 cmdControlDMC,
425 new DataRequestMonitor<IDMContext[]>(executor, drm) {
426 @Override
427 protected void handleSuccess() {
428 assert getData() != null;
429 assert getData().length == 1;
430 if (getData() == null || getData().length < 1) {
431 drm.done();
432 return;
433 }
434
435 // Choose the first process for now, until gdb can tell
436 // us which process the trace record is associated with.
437 IContainerDMContext containerDMC = (IContainerDMContext)(getData()[0]);
438 IBreakpointsTargetDMContext bpTargetDMC = DMContexts.getAncestorOfType(containerDMC , IBreakpointsTargetDMContext.class);
439
440 CommandFactory cmdFactory = tracker.getService(IMICommandControl.class).getCommandFactory();
441 IBreakpoints bpService = tracker.getService(MIBreakpoints.class);
442 if (cmdFactory == null || bpService == null) {
443 drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Could not find necessary services", null)); //$NON-NLS-1$
444 drm.done();
445 return;
446 }
447
448 // Execute the command
449 cmdControl.queueCommand(cmdFactory.createMIBreakList(bpTargetDMC),
450 new DataRequestMonitor<MIBreakListInfo>(executor, drm) {
451 @Override
452 protected void handleSuccess() {
453 MIBreakpoint[] breakpoints = getData().getMIBreakpoints();
454 for (int i = 0; i < breakpoints.length; i++) {
455 MIBreakpointDMData breakpoint = new MIBreakpointDMData(breakpoints[i]);
456 String type = breakpoint.getBreakpointType();
457 // Only save info if the current breakpoint is of type tracepoint
458 if(type.compareTo(MIBreakpoints.TRACEPOINT) == 0 ) {
459 fTpInfo.put(new Integer(breakpoint.getReference()), breakpoint);
460 }
461 }
462 drm.done();
463 }
464 });
465 }
466 });
467 }
468 };
469 try {
470 executor.execute(selectRecordQuery);
471 if (fIsTimeoutEnabled) {
472 selectRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocks until time out
473 } else {
474 selectRecordQuery.get(); // blocks
475 }
476 } catch (InterruptedException e) {
477 Activator.logError("Interruption exception", e); //$NON-NLS-1$
478 } catch (ExecutionException e) {
479 Activator.logError("GDB exception", e); //$NON-NLS-1$
480 } catch (RejectedExecutionException e) {
481 Activator.logError("Request rejected exception", e); //$NON-NLS-1$
482 } catch (TimeoutException e) {
483 Activator.logError("Timeout", e); //$NON-NLS-1$
484 } finally {
485 tracker.dispose();
486 }
487 }
488
489 /**
490 * Returns the number of frames contained in currently loaded tracepoint GDB
491 * session.
492 * <p>
493 * Note: A postmortem GDB session must be started before calling
494 * this method
495 *
496 * @return the number of frames contained in currently loaded tracepoint GDB
497 * session or zero in case of error
498 */
499 private synchronized int findNumFrames() {
500 int frameNum = 0;
501
502 if (DsfSession.getSession(fSessionId) == null) {
503 return 0;
504 }
505
506 final DsfExecutor executor = DsfSession.getSession(fSessionId)
507 .getExecutor();
508 final DsfServicesTracker tracker = new DsfServicesTracker(
509 GdbTraceCorePlugin.getBundleContext(), fSessionId);
510
511 Query<ITraceStatusDMData> selectRecordQuery = new Query<ITraceStatusDMData>() {
512 @Override
513 public void execute(
514 final DataRequestMonitor<ITraceStatusDMData> queryRm) {
515 final IGDBTraceControl traceControl = tracker
516 .getService(IGDBTraceControl.class);
517
518 final ICommandControlService commandControl = tracker
519 .getService(ICommandControlService.class);
520 final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl
521 .getContext();
522
523 if (traceControl != null) {
524 traceControl.getTraceStatus(dmc, queryRm);
525 } else {
526 queryRm.done();
527 }
528 }
529 };
530 try {
531 executor.execute(selectRecordQuery);
532 ITraceStatusDMData data;
533 if (fIsTimeoutEnabled) {
534 data = selectRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocks until time out
535 } else {
536 data = selectRecordQuery.get(); // blocks
537 }
538
539 frameNum = data.getNumberOfCollectedFrame();
540 } catch (InterruptedException e) {
541 Activator.logError("Interruption exception", e); //$NON-NLS-1$
542 } catch (ExecutionException e) {
543 Activator.logError("GDB exception", e); //$NON-NLS-1$
544 } catch (RejectedExecutionException e) {
545 Activator.logError("Request rejected exception", e); //$NON-NLS-1$
546 } catch (TimeoutException e) {
547 Activator.logError("Timeout", e); //$NON-NLS-1$
548 } finally {
549 tracker.dispose();
550 }
551 return frameNum;
552 }
553
554 /**
555 * This method uses the DSF-GDB interface to select a given frame number
556 * in the current GDB tracepoint session.
557 *
558 * @param rank the rank of the tracepoint frame to select.
559 * @param update true if visualization should be updated
560 * @return boolean true if select worked.
561 */
562 public boolean selectDataFrame(final long rank, final boolean update) {
563 boolean status = true;
564
565 final DsfSession dsfSession = DsfSession.getSession(fSessionId);
566 if (dsfSession == null) {
567 return false;
568 }
569
570 if (update) {
571 /*
572 * Clear the selection to ensure that the new selection is not
573 * prevented from overriding the current selection by the DSF
574 * selection policy. This could be removed when DSF provides
575 * an API to force the trace record selection in the Debug view.
576 */
577 Display.getDefault().syncExec(new Runnable() {
578 @Override
579 public void run() {
580 for (IWorkbenchWindow wbWindow : PlatformUI.getWorkbench().getWorkbenchWindows()) {
581 for (IWorkbenchPage wbPage : wbWindow.getPages()) {
582 IViewPart vp = wbPage.findView(IDebugUIConstants.ID_DEBUG_VIEW);
583 if (vp instanceof AbstractDebugView) {
584 Viewer viewer = ((AbstractDebugView) vp).getViewer();
585 if (viewer instanceof ITreeModelViewer) {
586 ((ITreeModelViewer) viewer).setSelection(StructuredSelection.EMPTY, false, true);
587 }
588 }
589 }
590 }
591 }
592 });
593 }
594
595 final DsfExecutor executor = dsfSession.getExecutor();
596 final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId);
597
598 Query<Object> selectRecordQuery = new Query<Object>() {
599 @Override
600 public void execute(final DataRequestMonitor<Object> queryRm) {
601 final IGDBTraceControl traceControl = tracker.getService(IGDBTraceControl.class);
602
603 final ICommandControlService commandControl = tracker.getService(ICommandControlService.class);
604 final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl.getContext();
605
606 if (traceControl != null) {
607 ITraceRecordDMContext newCtx = traceControl.createTraceRecordContext(dmc, Integer.toString((int) rank));
608 if (update) {
609 dsfSession.dispatchEvent(new TraceRecordSelectedChangedEvent(newCtx), new Hashtable<String, String>());
610 }
611 traceControl.selectTraceRecord(newCtx, queryRm);
612 } else {
613 queryRm.done();
614 }
615 }
616 };
617 try {
618 executor.execute(selectRecordQuery);
619 if (fIsTimeoutEnabled) {
620 selectRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocks until time out
621 } else {
622 selectRecordQuery.get(); // blocks
623 }
624 } catch (InterruptedException e) {
625 status = false;
626 Activator.logError("Interruption exception", e); //$NON-NLS-1$
627 } catch (ExecutionException e) {
628 status = false;
629 Activator.logError("GDB exception", e); //$NON-NLS-1$
630 } catch (RejectedExecutionException e) {
631 status = false;
632 Activator.logError("Request rejected exception", e); //$NON-NLS-1$
633 } catch (TimeoutException e) {
634 status = false;
635 Activator.logError("Timeout", e); //$NON-NLS-1$
636 } finally {
637 tracker.dispose();
638 }
639 return status;
640 }
641
642 /**
643 * This method uses DSF-GDB to read the currently selected GDB tracepoint
644 * data frame. An object of type GdbTraceEvent is build based on the
645 * information contained in the data frame and returned to the caller.
646 * <p>
647 * NOTE : A frame must be selected before calling this method!
648 *
649 * @param rank for internal purposes - does <b>not</b> control which
650 * frame will be read!
651 * @return parsed tp frame, in the form of a GdbTraceEvent
652 */
653 private GdbTraceEvent getTraceFrameData(final long rank) {
654
655 if (DsfSession.getSession(fSessionId) == null) {
656 return null;
657 }
658
659 final DsfExecutor executor = DsfSession.getSession(fSessionId).getExecutor();
660 final DsfServicesTracker tracker = new DsfServicesTracker(GdbTraceCorePlugin.getBundleContext(), fSessionId);
661
662 Query<ITraceRecordDMData> getFrameDataQuery = new Query<ITraceRecordDMData>() {
663 @Override
664 public void execute(final DataRequestMonitor<ITraceRecordDMData> rm) {
665 final IGDBTraceControl traceControl = tracker.getService(IGDBTraceControl.class);
666
667 final ICommandControlService commandControl = tracker.getService(ICommandControlService.class);
668 final ITraceTargetDMContext dmc = (ITraceTargetDMContext) commandControl.getContext();
669
670 if (traceControl != null) {
671 traceControl.getCurrentTraceRecordContext(dmc,
672 new DataRequestMonitor<ITraceRecordDMContext>(executor, rm) {
673 @Override
674 protected void handleSuccess() {
675 traceControl.getTraceRecordData(getData(), rm);
676 }
677 });
678 } else {
679 rm.done();
680 }
681 }
682 };
683 try {
684 // Execute the above query
685 executor.execute(getFrameDataQuery);
686 ITraceRecordDMData data;
687 if (fIsTimeoutEnabled) {
688 data = getFrameDataQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocking call until time out
689 } else {
690 data = getFrameDataQuery.get();
691 }
692
693 if (data == null) {
694 return null;
695 }
696
697 String ts = data.getTimestamp();
698 if (ts == null) {
699 ts = "0"; //$NON-NLS-1$
700 }
701
702 // get corresponding TP data
703 String tmfEventRef;
704 MIBreakpointDMData bp = fTpInfo.get(Integer.valueOf(data.getTracepointNumber()));
705 if (bp != null) {
706 tmfEventRef = bp.getFileName() + ":" + bp.getLineNumber() + " :: " + bp.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$
707 }
708 else {
709 tmfEventRef = tracedExecutable;
710 }
711
712 GdbTraceEventContent evContent = new GdbTraceEventContent(
713 data.getContent(),
714 Integer.parseInt(data.getTracepointNumber()),
715 Integer.parseInt(data.getRecordId()));
716
717 GdbTraceEvent ev = new GdbTraceEvent(fGdbTrace,
718 new TmfTimestamp(Integer.parseInt(data.getRecordId())),
719 "Tracepoint: " + data.getTracepointNumber() + ", Frame: " + data.getRecordId(), //$NON-NLS-1$ //$NON-NLS-2$
720 tmfEventType,
721 evContent,
722 tmfEventRef);
723
724 return ev;
725
726 } catch (InterruptedException e) {
727 return createExceptionEvent(rank, "Interruption exception"); //$NON-NLS-1$
728 } catch (java.util.concurrent.ExecutionException e) {
729 return createExceptionEvent(rank, "GDB exception"); //$NON-NLS-1$
730 } catch (RejectedExecutionException e) {
731 return createExceptionEvent(rank, "Request rejected exception"); //$NON-NLS-1$
732 } catch (TimeoutException e) {
733 return createExceptionEvent(rank, "Timeout"); //$NON-NLS-1$
734 }
735
736 finally {
737 tracker.dispose();
738 }
739 }
740
741 /**
742 * This is a helper method for getTraceFrameData, to create for it a
743 * "best effort" GdbTraceEvent when a problem occurs during the reading.
744 *
745 * @param rank long containing the number of the frame where the problem occurred
746 * @param message String containing a brief explanation of problem.
747 * @return a GdbTraceEvent object, filled as best as possible
748 */
749 private GdbTraceEvent createExceptionEvent(final long rank, final String message) {
750 // get corresponding TP data
751 String tmfEventRef;
752 String tmfEventSrc;
753 MIBreakpointDMData bp = fTpInfo.get(rank);
754 if (bp != null) {
755 tmfEventRef = bp.getFileName() + ":" + bp.getLineNumber() + " :: " + bp.getFunctionName(); //$NON-NLS-1$ //$NON-NLS-2$
756 tmfEventSrc = bp.getFileName() + " :: " + bp.getFunctionName() + ", line: " + bp.getLineNumber(); //$NON-NLS-1$ //$NON-NLS-2$
757 }
758 else {
759 tmfEventRef = tracedExecutable;
760 tmfEventSrc = "Tracepoint: n/a"; //$NON-NLS-1$
761 }
762
763 GdbTraceEventContent evContent = new GdbTraceEventContent("ERROR: " + message, 0, 0); //$NON-NLS-1$
764
765 GdbTraceEvent ev = new GdbTraceEvent(fGdbTrace,
766 new TmfTimestamp(rank),
767 tmfEventSrc,
768 tmfEventType,
769 evContent,
770 tmfEventRef);
771
772 return ev;
773 }
774
775 /**
776 * @return DSF-GDB session id of the current session.
777 */
778 public String getSessionId() {
779 return fSessionId;
780 }
781
782 /**
783 * Handler method that catches the DSF "record selected changed" event.
784 * It in turn creates a TMF "time sync" signal.
785 * @param event TraceRecordSelectedChangedEvent: The DSF event.
786 */
787 @DsfServiceEventHandler
788 public void handleDSFRecordSelectedEvents(final ITraceRecordSelectedChangedDMEvent event) {
789 if (event instanceof TraceRecordSelectedChangedEvent) {
790 TraceRecordSelectedChangedEvent traceEvent = (TraceRecordSelectedChangedEvent) event;
791 ITraceRecordDMContext context = traceEvent.getDMContext();
792 final String reference = context.getRecordId();
793 if (reference != null) {
794 int recordId = Integer.parseInt(reference);
795 selectGdbTraceEditor(context.getSessionId(), recordId);
796 }
797 }
798 }
799
800 private static void closeGdbTraceEditor(final String sessionId) {
801 Display.getDefault().asyncExec(new Runnable() {
802 @Override
803 public void run() {
804 for (IWorkbenchWindow wbWindow : PlatformUI.getWorkbench().getWorkbenchWindows()) {
805 for (IWorkbenchPage wbPage : wbWindow.getPages()) {
806 for (IEditorReference editorReference : wbPage.getEditorReferences()) {
807 IEditorPart editor = editorReference.getEditor(false);
808 if (editor instanceof ITmfTraceEditor) {
809 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
810 if (trace instanceof GdbTrace) {
811 if (((GdbTrace) trace).getDsfSessionId().equals(sessionId)) {
812 wbPage.closeEditor(editor, false);
813 }
814 }
815 }
816 }
817 }
818 }
819 }
820 });
821 }
822
823 private static void selectGdbTraceEditor(final String sessionId, final int recordId) {
824 Display.getDefault().asyncExec(new Runnable() {
825 @Override
826 public void run() {
827 for (IWorkbenchWindow wbWindow : PlatformUI.getWorkbench().getWorkbenchWindows()) {
828 for (IWorkbenchPage wbPage : wbWindow.getPages()) {
829 for (IEditorReference editorReference : wbPage.getEditorReferences()) {
830 IEditorPart editor = editorReference.getEditor(false);
831 if (editor instanceof ITmfTraceEditor) {
832 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
833 if (trace instanceof GdbTrace) {
834 if (((GdbTrace) trace).getDsfSessionId().equals(sessionId)) {
835 wbPage.bringToTop(editor);
836 if (recordId != -1) {
837 gotoRank(editor, recordId);
838 }
839 return;
840 }
841 } else if (trace instanceof TmfExperiment) {
842 TmfExperiment experiment = (TmfExperiment) trace;
843 int nbTraces = experiment.getTraces().length;
844 for (int i = 0; i < nbTraces; i++) {
845 GdbTrace gdbTrace = (GdbTrace) experiment.getTraces()[i];
846 if (gdbTrace.getDsfSessionId().equals(sessionId)) {
847 wbPage.bringToTop(editor);
848 if (recordId != -1) {
849 int rank = recordId * nbTraces + i;
850 gotoRank(editor, rank);
851 }
852 return;
853 }
854 }
855 }
856 }
857 }
858 }
859 }
860 }
861 });
862 }
863
864 private static void gotoRank(IEditorPart editor, int rank) {
865 IEditorInput editorInput = editor.getEditorInput();
866 if (editorInput instanceof IFileEditorInput) {
867 IFile file = ((IFileEditorInput) editorInput).getFile();
868 try {
869 final IMarker marker = file.createMarker(IMarker.MARKER);
870 marker.setAttribute(IMarker.LOCATION, (Integer) rank);
871 IDE.gotoMarker(editor, marker);
872 marker.delete();
873 } catch (CoreException e) {
874 e.printStackTrace();
875 }
876 }
877 }
878 }
This page took 0.052631 seconds and 5 git commands to generate.