pcap: Move plugins to their own sub-directory
[deliverable/tracecompass.git] / org.eclipse.tracecompass.gdbtrace.core / src / org / eclipse / tracecompass / internal / gdbtrace / core / trace / DsfGdbAdaptor.java
CommitLineData
6de2f761 1/*******************************************************************************
c19380ab 2 * Copyright (c) 2011, 2015 Ericsson
6de2f761
PT
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
ce800780 13 * Bernd Hufmann - Fixed deadlock during shutdown
6de2f761
PT
14 *******************************************************************************/
15
04c0d7d3 16package org.eclipse.tracecompass.internal.gdbtrace.core.trace;
6de2f761
PT
17
18import java.util.HashMap;
19import java.util.Hashtable;
20import java.util.List;
21import java.util.Map;
22import java.util.concurrent.ExecutionException;
23import java.util.concurrent.RejectedExecutionException;
e9a6e38e
MAL
24import java.util.concurrent.TimeUnit;
25import java.util.concurrent.TimeoutException;
6de2f761
PT
26
27import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
28import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
29import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
30import org.eclipse.cdt.dsf.concurrent.Query;
31import org.eclipse.cdt.dsf.datamodel.DMContexts;
32import org.eclipse.cdt.dsf.datamodel.IDMContext;
33import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
34import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
35import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
36import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
37import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
e9a6e38e 38import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
6de2f761 39import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
6de2f761
PT
40import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
41import org.eclipse.cdt.dsf.gdb.service.GDBTraceControl_7_2.TraceRecordSelectedChangedEvent;
42import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl;
43import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordDMContext;
44import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordDMData;
45import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent;
46import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceStatusDMData;
47import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext;
48import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
49import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
50import org.eclipse.cdt.dsf.mi.service.MIBreakpointDMData;
51import org.eclipse.cdt.dsf.mi.service.MIBreakpoints;
52import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
53import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo;
54import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint;
55import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
56import org.eclipse.cdt.dsf.service.DsfServicesTracker;
57import org.eclipse.cdt.dsf.service.DsfSession;
58import org.eclipse.core.resources.IFile;
59import org.eclipse.core.resources.IMarker;
60import org.eclipse.core.runtime.CoreException;
61import org.eclipse.core.runtime.IAdaptable;
62import org.eclipse.core.runtime.IPath;
63import org.eclipse.core.runtime.IStatus;
e9a6e38e 64import org.eclipse.core.runtime.Platform;
6de2f761
PT
65import org.eclipse.core.runtime.Status;
66import org.eclipse.debug.core.DebugException;
67import org.eclipse.debug.core.DebugPlugin;
68import org.eclipse.debug.core.ILaunch;
69import org.eclipse.debug.core.ILaunchConfigurationType;
70import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
71import org.eclipse.debug.core.ILaunchesListener2;
72import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
73import org.eclipse.debug.ui.AbstractDebugView;
74import org.eclipse.debug.ui.DebugUITools;
75import org.eclipse.debug.ui.IDebugUIConstants;
76import org.eclipse.debug.ui.contexts.DebugContextEvent;
77import org.eclipse.debug.ui.contexts.IDebugContextListener;
78import org.eclipse.jface.viewers.ISelection;
79import org.eclipse.jface.viewers.IStructuredSelection;
80import org.eclipse.jface.viewers.StructuredSelection;
81import org.eclipse.jface.viewers.Viewer;
6de2f761 82import org.eclipse.swt.widgets.Display;
04c0d7d3
AM
83import org.eclipse.tracecompass.internal.gdbtrace.core.GdbTraceCorePlugin;
84import org.eclipse.tracecompass.internal.gdbtrace.core.event.GdbTraceEvent;
85import org.eclipse.tracecompass.internal.gdbtrace.core.event.GdbTraceEventContent;
2bdf0193
AM
86import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
87import org.eclipse.tracecompass.tmf.core.event.TmfEventType;
88import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
89import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
5c5fa260 90import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
2bdf0193 91import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
6de2f761
PT
92import org.eclipse.ui.IEditorInput;
93import org.eclipse.ui.IEditorPart;
94import org.eclipse.ui.IEditorReference;
95import org.eclipse.ui.IFileEditorInput;
96import org.eclipse.ui.IViewPart;
97import org.eclipse.ui.IWorkbench;
98import org.eclipse.ui.IWorkbenchPage;
99import org.eclipse.ui.IWorkbenchWindow;
100import org.eclipse.ui.PlatformUI;
101import org.eclipse.ui.ide.IDE;
102
103/**
104 * Adaptor to access GDB Tracepoint frames, previously collected and saved in a
105 * file by GDB. One instance of this maps to a single DSF-GDB session.
106 * <p>
107 * This class offers the functions of starting a post-mortem GDB session with a
108 * tracepoint data file, navigate the data frames and return the data contained
109 * in a given tracepoint frame.
110 * <p>
111 * Note: GDB 7.2 or later is required to handle tracepoints
112 *
113 * @author Marc Dumais
114 * @author Francois Chouinard
115 */
116@SuppressWarnings("restriction")
117public class DsfGdbAdaptor {
118
119 private GdbTrace fGdbTrace;
120
121 private int fNumberOfFrames = 0;
e9a6e38e
MAL
122 private boolean fIsTimeoutEnabled;
123 private int fTimeout;
6de2f761
PT
124
125 private ILaunch fLaunch;
126 private boolean isTerminating;
127 private DsfSession fDsfSession = null;
128 private String fSessionId;
129
130 private String tracedExecutable = ""; //$NON-NLS-1$
131
132 private String gdb72Executable = ""; //$NON-NLS-1$
133 private String fTraceFilePath = ""; //$NON-NLS-1$
134 private String fTraceFile = ""; //$NON-NLS-1$
135 private String sourceLocator = ""; //$NON-NLS-1$
136
137 // To save tracepoints detailed info. The key is the rank of the
138 // breakpoint (tracepoint is a kind of breakpoint)
76faccfa 139 private Map<Integer, MIBreakpointDMData> fTpInfo = new HashMap<>();
6de2f761 140
e600c338 141 private TmfEventType tmfEventType = new TmfEventType("GDB Tracepoint", TmfEventField.makeRoot(new String[] { "Content" })); //$NON-NLS-1$ //$NON-NLS-2$
6de2f761 142
b82a2108
AM
143 {
144 new DsfGdbPlatformEventListener();
145 }
6de2f761
PT
146
147 /**
148 * <b><u>DsfGdbPlatformEventListener</u></b>
149 * <p>
150 * Listens to platform and DSF-GDB events that announce important events
151 * about the launchers or a change in debug context that we might need to
152 * react-to.
153 * <p>
154 * @author Francois Chouinard
155 */
e9a6e38e 156 private class DsfGdbPlatformEventListener implements
6de2f761
PT
157 ILaunchesListener2, IDebugContextListener {
158
159 /**
160 *
161 */
162 public DsfGdbPlatformEventListener() {
163 Display.getDefault().syncExec(new Runnable() {
164 @Override
165 public void run() {
166 DebugPlugin.getDefault().getLaunchManager().addLaunchListener(DsfGdbPlatformEventListener.this);
167 IWorkbench wb = PlatformUI.getWorkbench();
168 IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
169 DebugUITools.getDebugContextManager().getContextService(win).addDebugContextListener(DsfGdbPlatformEventListener.this);
170 }
171 });
172 }
173
174 @Override
175 public synchronized void launchesRemoved(ILaunch[] launches) {
176 }
177
178 @Override
179 public synchronized void launchesAdded(ILaunch[] launches) {
180 }
181
182 @Override
183 public synchronized void launchesChanged(ILaunch[] launches) {
184 }
185
186 @Override
187 public synchronized void launchesTerminated(ILaunch[] launches) {
188 for (ILaunch launch : launches) {
189 String sessionId = ((GdbLaunch) launch).getSession().getId();
190 closeGdbTraceEditor(sessionId);
191 }
192 }
193
194 private String fCurrentSessionId = ""; //$NON-NLS-1$
195 @Override
196 public void debugContextChanged(DebugContextEvent event) {
197 ISelection selection = event.getContext();
198 if (selection instanceof IStructuredSelection) {
199 List<?> eventContextList = ((IStructuredSelection) selection).toList();
200 for (Object eventContext : eventContextList) {
201 if (eventContext instanceof IAdaptable) {
34de057e
MAL
202 Object contextObject = ((IAdaptable) eventContext).getAdapter(IDMContext.class);
203 IDMContext context = (IDMContext) contextObject;
6de2f761
PT
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();
d5efe032 223 traceControl.getCurrentTraceRecordContext(traceContext, queryRm);
6de2f761
PT
224 } else {
225 queryRm.done();
226 }
227 }
228 };
229 try {
230 executor.execute(getCurrentRecordQuery);
e9a6e38e
MAL
231 ITraceRecordDMContext record;
232 if (DsfGdbAdaptor.this.fIsTimeoutEnabled) {
233 record = getCurrentRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS);
234 } else {
235 record = getCurrentRecordQuery.get();
236 }
6de2f761
PT
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) {
c19380ab 244 GdbTraceCorePlugin.logError("Interruption exception", e); //$NON-NLS-1$
e9a6e38e 245 } catch (ExecutionException e) {
c19380ab 246 GdbTraceCorePlugin.logError("GDB exception", e); //$NON-NLS-1$
6de2f761 247 } catch (RejectedExecutionException e) {
c19380ab 248 GdbTraceCorePlugin.logError("Request rejected exception", e); //$NON-NLS-1$
e9a6e38e 249 } catch (TimeoutException e) {
c19380ab 250 GdbTraceCorePlugin.logError("Timeout", e); //$NON-NLS-1$
6de2f761
PT
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 {
e9a6e38e
MAL
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 }
6de2f761
PT
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;
ce800780
BH
342 try {
343 fLaunch.terminate();
344 } catch (DebugException e) {
345 e.printStackTrace();
346 }
347 fLaunch = null;
6de2f761
PT
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 ) {
ec6cb556 458 fTpInfo.put(Integer.valueOf(breakpoint.getReference()), breakpoint);
6de2f761
PT
459 }
460 }
461 drm.done();
462 }
463 });
464 }
465 });
466 }
467 };
468 try {
469 executor.execute(selectRecordQuery);
e9a6e38e
MAL
470 if (fIsTimeoutEnabled) {
471 selectRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocks until time out
472 } else {
473 selectRecordQuery.get(); // blocks
474 }
6de2f761 475 } catch (InterruptedException e) {
c19380ab 476 GdbTraceCorePlugin.logError("Interruption exception", e); //$NON-NLS-1$
6de2f761 477 } catch (ExecutionException e) {
c19380ab 478 GdbTraceCorePlugin.logError("GDB exception", e); //$NON-NLS-1$
e9a6e38e 479 } catch (RejectedExecutionException e) {
c19380ab 480 GdbTraceCorePlugin.logError("Request rejected exception", e); //$NON-NLS-1$
e9a6e38e 481 } catch (TimeoutException e) {
c19380ab 482 GdbTraceCorePlugin.logError("Timeout", e); //$NON-NLS-1$
6de2f761
PT
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);
e9a6e38e
MAL
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
6de2f761
PT
538 frameNum = data.getNumberOfCollectedFrame();
539 } catch (InterruptedException e) {
c19380ab 540 GdbTraceCorePlugin.logError("Interruption exception", e); //$NON-NLS-1$
e9a6e38e 541 } catch (ExecutionException e) {
c19380ab 542 GdbTraceCorePlugin.logError("GDB exception", e); //$NON-NLS-1$
6de2f761 543 } catch (RejectedExecutionException e) {
c19380ab 544 GdbTraceCorePlugin.logError("Request rejected exception", e); //$NON-NLS-1$
e9a6e38e 545 } catch (TimeoutException e) {
c19380ab 546 GdbTraceCorePlugin.logError("Timeout", e); //$NON-NLS-1$
6de2f761
PT
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);
e9a6e38e
MAL
618 if (fIsTimeoutEnabled) {
619 selectRecordQuery.get(fTimeout, TimeUnit.MILLISECONDS); // blocks until time out
620 } else {
621 selectRecordQuery.get(); // blocks
622 }
6de2f761
PT
623 } catch (InterruptedException e) {
624 status = false;
c19380ab 625 GdbTraceCorePlugin.logError("Interruption exception", e); //$NON-NLS-1$
e9a6e38e 626 } catch (ExecutionException e) {
6de2f761 627 status = false;
c19380ab 628 GdbTraceCorePlugin.logError("GDB exception", e); //$NON-NLS-1$
6de2f761
PT
629 } catch (RejectedExecutionException e) {
630 status = false;
c19380ab 631 GdbTraceCorePlugin.logError("Request rejected exception", e); //$NON-NLS-1$
e9a6e38e
MAL
632 } catch (TimeoutException e) {
633 status = false;
c19380ab 634 GdbTraceCorePlugin.logError("Timeout", e); //$NON-NLS-1$
6de2f761
PT
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);
e9a6e38e
MAL
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 }
6de2f761
PT
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$
e9a6e38e
MAL
731 } catch (TimeoutException e) {
732 return createExceptionEvent(rank, "Timeout"); //$NON-NLS-1$
6de2f761
PT
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;
fa62dc1d
BH
842 List<ITmfTrace> expTraces = experiment.getTraces();
843 int nbTraces = expTraces.size();
6de2f761 844 for (int i = 0; i < nbTraces; i++) {
fa62dc1d 845 GdbTrace gdbTrace = (GdbTrace) expTraces.get(i);
6de2f761
PT
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 }
c19380ab 878}
This page took 0.093501 seconds and 5 git commands to generate.