From c8835a2f9519c6c835278629177401dda09f3062 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Wed, 28 Apr 2010 23:50:54 +0000 Subject: [PATCH] Bug 284286: Trace Record visualization for DSF-GDB --- .../plugin.properties | 6 + dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml | 36 + .../gdb/internal/ui/GdbAdapterFactory.java | 16 +- .../GdbSelectNextTraceRecordCommand.java | 167 +++++ .../GdbSelectPrevTraceRecordCommand.java | 167 +++++ .../SelectNextTraceRecordCommandHandler.java | 26 + .../SelectPrevTraceRecordCommandHandler.java | 26 + .../gdb/internal/ui/launching/CMainTab.java | 151 +++- .../META-INF/MANIFEST.MF | 1 + .../gdb/IGDBLaunchConfigurationConstants.java | 31 +- .../ISelectNextTraceRecordHandler.java | 21 + .../ISelectPrevTraceRecordHandler.java | 21 + .../events/MITracepointSelectedEvent.java | 84 +++ .../service/command/events/Messages.java | 32 + .../command/events/messages.properties | 13 + .../gdb/launching/FinalLaunchSequence.java | 52 +- .../dsf/gdb/launching/GdbLaunchDelegate.java | 42 +- .../gdb/launching/LaunchMessages.properties | 9 +- .../cdt/dsf/gdb/service/GDBProcesses_7_0.java | 12 + .../dsf/gdb/service/GDBRunControl_7_0.java | 26 +- .../dsf/gdb/service/GDBRunControl_7_0_NS.java | 5 + ...trol_7_1.java => GDBTraceControl_7_2.java} | 679 +++++++++++------- .../gdb/service/GdbDebugServicesFactory.java | 14 +- .../cdt/dsf/gdb/service/IGDBTraceControl.java | 55 +- .../gdb/service/command/GDBControl_7_0.java | 14 +- .../cdt/dsf/mi/service/MIExpressions.java | 24 + .../cdt/dsf/mi/service/MIRunControl.java | 5 + .../eclipse/cdt/dsf/mi/service/MIStack.java | 194 ++++- .../cdt/dsf/mi/service/MIVariableManager.java | 30 +- .../mi/service/command/AbstractMIControl.java | 9 +- .../mi/service/command/CommandFactory.java | 6 + .../service/command/commands/MITraceFind.java | 62 ++ .../command/output/MITraceFindInfo.java | 57 ++ .../service/command/output/MITraceRecord.java | 73 ++ 34 files changed, 1807 insertions(+), 359 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbSelectNextTraceRecordCommand.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbSelectPrevTraceRecordCommand.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/SelectNextTraceRecordCommandHandler.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/SelectPrevTraceRecordCommandHandler.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/ISelectNextTraceRecordHandler.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/ISelectPrevTraceRecordHandler.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/MITracepointSelectedEvent.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/Messages.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/messages.properties rename dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/{GDBTraceControl_7_1.java => GDBTraceControl_7_2.java} (51%) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MITraceFind.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MITraceFindInfo.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MITraceRecord.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties index 2cc43c30b4c..3da35534847 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.properties @@ -40,3 +40,9 @@ view.traceControl.name=Trace Control toolbar.startTracing.name=Start Tracing toolbar.stopTracing.name=Stop Tracing toolbar.saveTracing.name=Save Trace Data +toolbar.nextTraceRecord.label=Next Trace Record +toolbar.prevTraceRecord.label=Previous Trace Record +command.nextTraceRecord.name=Next Trace Record +command.prevTraceRecord.name=Previous Trace Record +command.nextTraceRecord.description=Select Next Trace Record +command.prevTraceRecord.description=Select Previous Trace Record diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml index 7651c60e300..b823868451c 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/plugin.xml @@ -353,6 +353,30 @@ + + + + + + + + + + + + + + + + diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java index 10cc1b01b68..a6fb1aa2a24 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java @@ -40,6 +40,8 @@ import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.DefaultRefreshAllTarget; import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.IRefreshAllTarget; import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.DefaultDsfModelSelectionPolicyFactory; import org.eclipse.cdt.dsf.gdb.actions.IConnect; +import org.eclipse.cdt.dsf.gdb.internal.commands.ISelectNextTraceRecordHandler; +import org.eclipse.cdt.dsf.gdb.internal.commands.ISelectPrevTraceRecordHandler; import org.eclipse.cdt.dsf.gdb.internal.ui.actions.DsfTerminateCommand; import org.eclipse.cdt.dsf.gdb.internal.ui.actions.GdbConnectCommand; import org.eclipse.cdt.dsf.gdb.internal.ui.actions.GdbDisconnectCommand; @@ -51,6 +53,8 @@ import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbReverseStepIntoCommand; import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbReverseStepOverCommand; import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbReverseToggleCommand; import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbSaveTraceDataCommand; +import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbSelectNextTraceRecordCommand; +import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbSelectPrevTraceRecordCommand; import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbStartTracingCommand; import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbStopTracingCommand; import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbUncallCommand; @@ -119,6 +123,8 @@ public class GdbAdapterFactory final GdbStartTracingCommand fStartTracingTarget; final GdbStopTracingCommand fStopTracingTarget; final GdbSaveTraceDataCommand fSaveTraceDataTarget; + final GdbSelectNextTraceRecordCommand fSelectNextRecordTarget; + final GdbSelectPrevTraceRecordCommand fSelectPrevRecordTarget; final GdbDebugTextHover fDebugTextHover; SessionAdapterSet(GdbLaunch launch) { @@ -161,6 +167,8 @@ public class GdbAdapterFactory fStartTracingTarget = new GdbStartTracingCommand(session); fStopTracingTarget = new GdbStopTracingCommand(session); fSaveTraceDataTarget = new GdbSaveTraceDataCommand(session); + fSelectNextRecordTarget = new GdbSelectNextTraceRecordCommand(session); + fSelectPrevRecordTarget = new GdbSelectPrevTraceRecordCommand(session); session.registerModelAdapter(ISteppingModeTarget.class, fSteppingModeTarget); session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand); @@ -183,6 +191,8 @@ public class GdbAdapterFactory session.registerModelAdapter(IStartTracingHandler.class, fStartTracingTarget); session.registerModelAdapter(IStopTracingHandler.class, fStopTracingTarget); session.registerModelAdapter(ISaveTraceDataHandler.class, fSaveTraceDataTarget); + session.registerModelAdapter(ISelectNextTraceRecordHandler.class, fSelectNextRecordTarget); + session.registerModelAdapter(ISelectPrevTraceRecordHandler.class, fSelectPrevRecordTarget); fDebugModelProvider = new IDebugModelProvider() { // @see org.eclipse.debug.core.model.IDebugModelProvider#getModelIdentifiers() @@ -238,7 +248,9 @@ public class GdbAdapterFactory session.unregisterModelAdapter(IStartTracingHandler.class); session.unregisterModelAdapter(IStopTracingHandler.class); session.unregisterModelAdapter(ISaveTraceDataHandler.class); - + session.unregisterModelAdapter(ISelectNextTraceRecordHandler.class); + session.unregisterModelAdapter(ISelectPrevTraceRecordHandler.class); + session.unregisterModelAdapter(ICEditorTextHover.class); fSteppingModeTarget.dispose(); @@ -261,6 +273,8 @@ public class GdbAdapterFactory fStartTracingTarget.dispose(); fStopTracingTarget.dispose(); fSaveTraceDataTarget.dispose(); + fSelectNextRecordTarget.dispose(); + fSelectPrevRecordTarget.dispose(); } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbSelectNextTraceRecordCommand.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbSelectNextTraceRecordCommand.java new file mode 100644 index 00000000000..168aa3c437b --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbSelectNextTraceRecordCommand.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.ui.commands; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.gdb.internal.commands.ISelectNextTraceRecordHandler; +import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordDMContext; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceStatusDMData; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.IRequest; +import org.eclipse.debug.core.commands.AbstractDebugCommand; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; + +/** + * Command to select the next trace record + * + * @since 2.1 + */ +public class GdbSelectNextTraceRecordCommand extends AbstractDebugCommand implements ISelectNextTraceRecordHandler { + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public GdbSelectNextTraceRecordCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(GdbUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + @Override + protected void doExecute(Object[] targets, IProgressMonitor monitor, IRequest request) throws CoreException { + if (targets.length != 1) { + return; + } + + final ITraceTargetDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)targets[0]).getDMContext(), ITraceTargetDMContext.class); + if (dmc == null) { + return; + } + + Query selectRecordQuery = new Query() { + @Override + public void execute(final DataRequestMonitor rm) { + final IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class); + + if (traceControl != null) { + traceControl.getCurrentTraceRecordContext( + dmc, + new DataRequestMonitor(fExecutor, rm) { + @Override + protected void handleSuccess() { + ITraceRecordDMContext nextDmc = traceControl.createNextRecordContext(getData()); + traceControl.selectTraceRecord(nextDmc, rm); + }; + }); + } else { + rm.done(); + } + } + }; + try { + fExecutor.execute(selectRecordQuery); + selectRecordQuery.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } catch (RejectedExecutionException e) { + // Can be thrown if the session is shutdown + } + } + + @Override + protected boolean isExecutable(Object[] targets, IProgressMonitor monitor, IEnabledStateRequest request) + throws CoreException + { + if (targets.length != 1) { + return false; + } + + final ITraceTargetDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)targets[0]).getDMContext(), ITraceTargetDMContext.class); + if (dmc == null) { + return false; + } + + Query canSelectRecordQuery = new Query() { + @Override + public void execute(final DataRequestMonitor rm) { + IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class); + + if (traceControl != null) { + traceControl.getTraceStatus(dmc, new DataRequestMonitor(fExecutor, rm) { + @Override + protected void handleSuccess() { + if (getData().getNumberOfCollectedFrame() > 0) { + IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class); + if (traceControl != null) { + traceControl.isTracing(dmc, new DataRequestMonitor(fExecutor, rm) { + @Override + protected void handleSuccess() { + rm.setData(!getData()); + rm.done(); + }; + }); + } else { + rm.setData(false); + rm.done(); + } + } else { + rm.setData(false); + rm.done(); + } + }; + }); + } else { + rm.setData(false); + rm.done(); + } + } + }; + try { + fExecutor.execute(canSelectRecordQuery); + return canSelectRecordQuery.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } catch (RejectedExecutionException e) { + // Can be thrown if the session is shutdown + } + + return false; + } + + @Override + protected Object getTarget(Object element) { + if (element instanceof IDMVMContext) { + return element; + } + return null; + } + + @Override + protected boolean isRemainEnabled(IDebugCommandRequest request) { + return true; + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbSelectPrevTraceRecordCommand.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbSelectPrevTraceRecordCommand.java new file mode 100644 index 00000000000..e5c5df5fc37 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbSelectPrevTraceRecordCommand.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.ui.commands; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.DsfExecutor; +import org.eclipse.cdt.dsf.concurrent.Query; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.gdb.internal.commands.ISelectPrevTraceRecordHandler; +import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordDMContext; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceStatusDMData; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext; +import org.eclipse.cdt.dsf.service.DsfServicesTracker; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.debug.core.IRequest; +import org.eclipse.debug.core.commands.AbstractDebugCommand; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; + +/** + * Command to select the previous trace record + * + * @since 2.1 + */ +public class GdbSelectPrevTraceRecordCommand extends AbstractDebugCommand implements ISelectPrevTraceRecordHandler { + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public GdbSelectPrevTraceRecordCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(GdbUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + @Override + protected void doExecute(Object[] targets, IProgressMonitor monitor, IRequest request) throws CoreException { + if (targets.length != 1) { + return; + } + + final ITraceTargetDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)targets[0]).getDMContext(), ITraceTargetDMContext.class); + if (dmc == null) { + return; + } + + Query selectRecordQuery = new Query() { + @Override + public void execute(final DataRequestMonitor rm) { + final IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class); + + if (traceControl != null) { + traceControl.getCurrentTraceRecordContext( + dmc, + new DataRequestMonitor(fExecutor, rm) { + @Override + protected void handleSuccess() { + ITraceRecordDMContext prevDmc = traceControl.createPrevRecordContext(getData()); + traceControl.selectTraceRecord(prevDmc, rm); + }; + }); + } else { + rm.done(); + } + } + }; + try { + fExecutor.execute(selectRecordQuery); + selectRecordQuery.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } catch (RejectedExecutionException e) { + // Can be thrown if the session is shutdown + } + } + + @Override + protected boolean isExecutable(Object[] targets, IProgressMonitor monitor, IEnabledStateRequest request) + throws CoreException + { + if (targets.length != 1) { + return false; + } + + final ITraceTargetDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)targets[0]).getDMContext(), ITraceTargetDMContext.class); + if (dmc == null) { + return false; + } + + Query canSelectRecordQuery = new Query() { + @Override + public void execute(final DataRequestMonitor rm) { + IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class); + + if (traceControl != null) { + traceControl.getTraceStatus(dmc, new DataRequestMonitor(fExecutor, rm) { + @Override + protected void handleSuccess() { + if (getData().getNumberOfCollectedFrame() > 0) { + IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class); + if (traceControl != null) { + traceControl.isTracing(dmc, new DataRequestMonitor(fExecutor, rm) { + @Override + protected void handleSuccess() { + rm.setData(!getData()); + rm.done(); + }; + }); + } else { + rm.setData(false); + rm.done(); + } + } else { + rm.setData(false); + rm.done(); + } + }; + }); + } else { + rm.setData(false); + rm.done(); + } + } + }; + try { + fExecutor.execute(canSelectRecordQuery); + return canSelectRecordQuery.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } catch (RejectedExecutionException e) { + // Can be thrown if the session is shutdown + } + + return false; + } + + @Override + protected Object getTarget(Object element) { + if (element instanceof IDMVMContext) { + return element; + } + return null; + } + + @Override + protected boolean isRemainEnabled(IDebugCommandRequest request) { + return true; + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/SelectNextTraceRecordCommandHandler.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/SelectNextTraceRecordCommandHandler.java new file mode 100644 index 00000000000..b3b5b2560fd --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/SelectNextTraceRecordCommandHandler.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.ui.commands; + +import org.eclipse.cdt.dsf.gdb.internal.commands.ISelectNextTraceRecordHandler; +import org.eclipse.debug.ui.actions.DebugCommandHandler; + +/** + * Command handler to select the next trace record + * + * @since 2.1 + */ +public class SelectNextTraceRecordCommandHandler extends DebugCommandHandler { + @Override + protected Class getCommandType() { + return ISelectNextTraceRecordHandler.class; + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/SelectPrevTraceRecordCommandHandler.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/SelectPrevTraceRecordCommandHandler.java new file mode 100644 index 00000000000..8f35a2a9566 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/SelectPrevTraceRecordCommandHandler.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.ui.commands; + +import org.eclipse.cdt.dsf.gdb.internal.commands.ISelectPrevTraceRecordHandler; +import org.eclipse.debug.ui.actions.DebugCommandHandler; + +/** + * Command handler to select the previous trace record + * + * @since 2.1 + */ +public class SelectPrevTraceRecordCommandHandler extends DebugCommandHandler { + @Override + protected Class getCommandType() { + return ISelectPrevTraceRecordHandler.class; + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java index 1f3379d1074..f4f8307cf92 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/CMainTab.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 QNX Software Systems and others. + * Copyright (c) 2008, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - initial API and implementation * Ken Ryall (Nokia) - bug 178731 + * Ericsson - Support for tracepoint post-mortem debugging *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal.ui.launching; @@ -17,6 +18,7 @@ import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; import org.eclipse.cdt.dsf.gdb.launching.LaunchMessages; import org.eclipse.cdt.launch.ui.CAbstractMainTab; @@ -39,11 +41,14 @@ import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.dialogs.TwoPaneElementSelector; @@ -66,7 +71,18 @@ public class CMainTab extends CAbstractMainTab { * @since 2.0 */ public static final String TAB_ID = "org.eclipse.cdt.dsf.gdb.launch.mainTab"; //$NON-NLS-1$ - + + private static final String CORE_FILE = LaunchMessages.getString("CMainTab.CoreFile_type"); //$NON-NLS-1$ + private static final String TRACE_FILE = LaunchMessages.getString("CMainTab.TraceFile_type"); //$NON-NLS-1$ + + /** + * Combo box to select which type of post mortem file should be used. + * We currently support core files and trace files. + * + * @since 2.1 + */ + protected Combo fCoreTypeCombo; + private final boolean fDontCheckProgram; private final boolean fSpecifyCoreFile; private final boolean fIncludeBuildSettings; @@ -151,7 +167,7 @@ public class CMainTab extends CAbstractMainTab { browseForBinaryButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent evt) { - String text = handleBrowseButtonSelected(); + String text = handleBrowseButtonSelected(LaunchMessages.getString("CMaintab.Application_Selection")); //$NON-NLS-1$ if (text != null) { fProgText.setText(text); } @@ -160,6 +176,92 @@ public class CMainTab extends CAbstractMainTab { }); } + /* + * Overridden to add the possibility to choose a trace file as a post mortem debug file. + */ + /** @since 2.1 */ + @Override + protected void createCoreFileGroup(Composite parent, int colSpan) { + Composite coreComp = new Composite(parent, SWT.NONE); + GridLayout coreLayout = new GridLayout(); + coreLayout.numColumns = 3; + coreLayout.marginHeight = 0; + coreLayout.marginWidth = 0; + coreComp.setLayout(coreLayout); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = colSpan; + coreComp.setLayoutData(gd); + + Label comboLabel = new Label(coreComp, SWT.NONE); + comboLabel.setText(LaunchMessages.getString("CMainTab.Post_mortem_file_type")); //$NON-NLS-1$ + comboLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); + + fCoreTypeCombo = new Combo(coreComp, SWT.READ_ONLY | SWT.DROP_DOWN); + fCoreTypeCombo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); + fCoreTypeCombo.add(CORE_FILE); + fCoreTypeCombo.add(TRACE_FILE); + + fCoreLabel = new Label(coreComp, SWT.NONE); + fCoreLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1)); + fCoreText = new Text(coreComp, SWT.SINGLE | SWT.BORDER); + gd = new GridData(GridData.FILL_HORIZONTAL); + fCoreText.setLayoutData(gd); + fCoreText.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent evt) { + updateLaunchConfigurationDialog(); + } + }); + + Button browseForCoreButton; + browseForCoreButton = createPushButton(coreComp, LaunchMessages.getString("Launch.common.Browse_2"), null); //$NON-NLS-1$ + browseForCoreButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent evt) { + String text; + String coreType = getSelectedCoreType(); + if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) { + text = handleBrowseButtonSelected(LaunchMessages.getString("CMaintab.Core_Selection")); //$NON-NLS-1$ + } else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) { + text = handleBrowseButtonSelected(LaunchMessages.getString("CMaintab.Trace_Selection")); //$NON-NLS-1$ + } else { + assert false : "Unknown core file type"; //$NON-NLS-1$ + text = handleBrowseButtonSelected(LaunchMessages.getString("CMaintab.Core_Selection")); //$NON-NLS-1$ + } + + if (text != null) { + fCoreText.setText(text); + } + updateLaunchConfigurationDialog(); + } + }); + + fCoreTypeCombo.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + updateCoreFileLabel(); + updateLaunchConfigurationDialog(); + } + + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + fCoreTypeCombo.select(0); + } + + /** + * Show a dialog that lets the user select a file. + * This method allows to set the title of the dialog. + * + * @param title The title the dialog should show. + * + * @since 2.1 + */ + protected String handleBrowseButtonSelected(String title) { + FileDialog fileDialog = new FileDialog(getShell(), SWT.NONE); + fileDialog.setText(title); + fileDialog.setFileName(fProgText.getText()); + return fileDialog.open(); + } + /* * (non-Javadoc) * @@ -177,12 +279,50 @@ public class CMainTab extends CAbstractMainTab { protected void updateCoreFromConfig(ILaunchConfiguration config) { if (fCoreText != null) { String coreName = EMPTY_STRING; + String coreType = IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT; try { coreName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, EMPTY_STRING); + coreType = config.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE, + IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT); } catch (CoreException ce) { GdbUIPlugin.log(ce); } fCoreText.setText(coreName); + if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) { + fCoreTypeCombo.setText(CORE_FILE); + } else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) { + fCoreTypeCombo.setText(TRACE_FILE); + } else { + assert false : "Unknown core file type"; //$NON-NLS-1$ + fCoreTypeCombo.setText(CORE_FILE); + } + updateCoreFileLabel(); + } + } + + /** @since 2.1 */ + protected String getSelectedCoreType() { + int selectedIndex = fCoreTypeCombo.getSelectionIndex(); + if (fCoreTypeCombo.getItem(selectedIndex).equals(CORE_FILE)) { + return IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE; + } else if (fCoreTypeCombo.getItem(selectedIndex).equals(TRACE_FILE)) { + return IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE; + } else { + assert false : "Unknown post mortem file type"; //$NON-NLS-1$ + return IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE; + } + } + + /** @since 2.1 */ + protected void updateCoreFileLabel() { + String coreType = getSelectedCoreType(); + if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) { + fCoreLabel.setText(LaunchMessages.getString("CMainTab.CoreFile_path")); //$NON-NLS-1$ + } else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) { + fCoreLabel.setText(LaunchMessages.getString("CMainTab.TraceFile_path")); //$NON-NLS-1$ + } else { + assert false : "Unknown post mortem file type"; //$NON-NLS-1$ + fCoreLabel.setText(LaunchMessages.getString("CMainTab.CoreFile_path")); //$NON-NLS-1$ } } @@ -206,6 +346,7 @@ public class CMainTab extends CAbstractMainTab { config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, fProgText.getText()); if (fCoreText != null) { config.setAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, fCoreText.getText()); + config.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE, getSelectedCoreType()); } } @@ -350,12 +491,12 @@ public class CMainTab extends CAbstractMainTab { // This allows to re-use the launch, with a different core file. if (!coreName.equals(EMPTY_STRING)) { if (coreName.equals(".") || coreName.equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$ - setErrorMessage(LaunchMessages.getString("CMainTab.Core_does_not_exist")); //$NON-NLS-1$ + setErrorMessage(LaunchMessages.getString("CMainTab.File_does_not_exist")); //$NON-NLS-1$ return false; } IPath corePath = new Path(coreName); if (!corePath.toFile().exists()) { - setErrorMessage(LaunchMessages.getString("CMainTab.Core_does_not_exist")); //$NON-NLS-1$ + setErrorMessage(LaunchMessages.getString("CMainTab.File_does_not_exist")); //$NON-NLS-1$ return false; } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF b/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF index 5d16e1ac84a..90536f4d3b8 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF @@ -20,6 +20,7 @@ Bundle-RequiredExecutionEnvironment: J2SE-1.5 Export-Package: org.eclipse.cdt.dsf.gdb, org.eclipse.cdt.dsf.gdb.actions, org.eclipse.cdt.dsf.gdb.breakpoints, + org.eclipse.cdt.dsf.gdb.internal.commands, org.eclipse.cdt.dsf.gdb.launching, org.eclipse.cdt.dsf.gdb.service, org.eclipse.cdt.dsf.gdb.service.command, diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGDBLaunchConfigurationConstants.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGDBLaunchConfigurationConstants.java index 5daee719166..2bf84b89c6e 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGDBLaunchConfigurationConstants.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGDBLaunchConfigurationConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 Ericsson and others. + * Copyright (c) 2008, 2010 Ericsson and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -90,6 +90,13 @@ public class IGDBLaunchConfigurationConstants { */ public static final String ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND = GdbPlugin.PLUGIN_ID + ".UPDATE_THREADLIST_ON_SUSPEND"; //$NON-NLS-1$ + /** + * Launch configuration attribute key. The value is a String specifying the type of post mortem launch. + * @since 3.0 + */ + public static final String ATTR_DEBUGGER_POST_MORTEM_TYPE = GdbPlugin.PLUGIN_ID + ".POST_MORTEM_TYPE"; //$NON-NLS-1$ + + /** * Launch configuration attribute value. The key is ATTR_DEBUG_NAME. */ @@ -131,4 +138,26 @@ public class IGDBLaunchConfigurationConstants { */ public static final boolean DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT = false; + /** + * Possible attribute value for the key is ATTR_DEBUGGER_POST_MORTEM_TYPE. + * Indicates a core file. + * + * @since 3.0 + */ + public static final String DEBUGGER_POST_MORTEM_CORE_FILE = "CORE_FILE"; //$NON-NLS-1$ + + /** + * Possible attribute value for the key is ATTR_DEBUGGER_POST_MORTEM_TYPE. + * Indicates a trace data file. + * + * @since 3.0 + */ + public static final String DEBUGGER_POST_MORTEM_TRACE_FILE = "TRACE_FILE"; //$NON-NLS-1$ + + /** + * Launch configuration attribute value. The key is ATTR_DEBUGGER_POST_MORTEM_TYPE. + * @since 3.0 + */ + public static final String DEBUGGER_POST_MORTEM_TYPE_DEFAULT = DEBUGGER_POST_MORTEM_CORE_FILE; + } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/ISelectNextTraceRecordHandler.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/ISelectNextTraceRecordHandler.java new file mode 100644 index 00000000000..f9a4c36392e --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/ISelectNextTraceRecordHandler.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.commands; + +import org.eclipse.debug.core.commands.IDebugCommandHandler; + +/** + * Handler interface to select the next trace record. + * + * @since 3.0 + */ +public interface ISelectNextTraceRecordHandler extends IDebugCommandHandler { +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/ISelectPrevTraceRecordHandler.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/ISelectPrevTraceRecordHandler.java new file mode 100644 index 00000000000..3809cdf4c95 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/ISelectPrevTraceRecordHandler.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.commands; + +import org.eclipse.debug.core.commands.IDebugCommandHandler; + +/** + * Handler interface to select the previous trace record. + * + * @since 3.0 + */ +public interface ISelectPrevTraceRecordHandler extends IDebugCommandHandler { +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/MITracepointSelectedEvent.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/MITracepointSelectedEvent.java new file mode 100644 index 00000000000..13a941a0861 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/MITracepointSelectedEvent.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.service.command.events; + +import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.cdt.dsf.concurrent.Immutable; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.mi.service.command.events.MIBreakpointHitEvent; +import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; +import org.eclipse.cdt.dsf.mi.service.command.output.MIConst; +import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame; +import org.eclipse.cdt.dsf.mi.service.command.output.MIResult; +import org.eclipse.cdt.dsf.mi.service.command.output.MIValue; + +/** + * Conveys that gdb has selected a new tracepoint record. Although this + * is a response to an MI command, we trigger an MI event internally + * because it should cause the same behaviour as if we stopped at a + * breakpoint. The output record looks like this: + * + * + * ^done,found="1",tracepoint="1",traceframe="0",frame={level="0",addr="0x08048900",func="foo",args=[{name="i",value="2"}],file="file.cpp",fullname="/home/marc/file.cpp",line="505"} + + * + * @since 3.0 + */ +@Immutable +public class MITracepointSelectedEvent extends MIBreakpointHitEvent { + + private int fRecNo; + + protected MITracepointSelectedEvent(IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame, int trptno, int recordno) { + super(ctx, token, results, frame, trptno); + fRecNo = recordno; + } + + /** + * Returns a text to display for the reason why we show the debug view as stopped. + */ + public String getReason() { + return Messages.Tracepoint + " " + getNumber() + //$NON-NLS-1$ + ", " + Messages.Record + " " + fRecNo; //$NON-NLS-1$ //$NON-NLS-2$ + } + + @ConfinedToDsfExecutor("") + public static MITracepointSelectedEvent parse(IExecutionDMContext dmc, int token, MIResult[] results) { + int trptno = -1; + int recordno = -1; + + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value != null && value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + + if (var.equals("tracepoint")) { //$NON-NLS-1$ + try { + trptno = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("traceframe")) { //$NON-NLS-1$ + try { + recordno = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + + } + + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(dmc, token, results); + return new MITracepointSelectedEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), trptno, recordno); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/Messages.java new file mode 100644 index 00000000000..54192eadb8c --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/Messages.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.gdb.internal.service.command.events; + +import org.eclipse.osgi.util.NLS; + +/** + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.gdb.internal.service.command.events.messages"; //$NON-NLS-1$ + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } + + public static String Tracepoint; + public static String Record; +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/messages.properties new file mode 100644 index 00000000000..d24dae1bfa6 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/command/events/messages.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2010 Ericsson and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Ericsson - initial API and implementation +############################################################################### + +Tracepoint=Tracepoint +Record=Record diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java index a06e867254d..806af5d6eef 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java @@ -21,6 +21,7 @@ import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfExecutor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.Sequence; +import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.DataModelInitializedEvent; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; @@ -29,6 +30,8 @@ import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.actions.IConnect; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext; import org.eclipse.cdt.dsf.gdb.service.SessionType; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; import org.eclipse.cdt.dsf.mi.service.CSourceLookup; @@ -370,31 +373,60 @@ public class FinalLaunchSequence extends Sequence { if (fSessionType == SessionType.CORE) { try { String coreFile = fLaunch.getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, ""); //$NON-NLS-1$ - + final String coreType = fLaunch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE, + IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT); if (coreFile.length() == 0) { new PromptForCoreJob( - "Prompt for core file", //$NON-NLS-1$ + "Prompt for post mortem file", //$NON-NLS-1$ new DataRequestMonitor(getExecutor(), requestMonitor) { @Override protected void handleSuccess() { String newCoreFile = getData(); if (newCoreFile == null || newCoreFile.length()== 0) { - requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get core file path", null)); //$NON-NLS-1$ + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get post mortem file path", null)); //$NON-NLS-1$ requestMonitor.done(); } else { - fCommandControl.queueCommand( - fCommandFactory.createMITargetSelectCore(fCommandControl.getContext(), newCoreFile), - new DataRequestMonitor(getExecutor(), requestMonitor)); + if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) { + fCommandControl.queueCommand( + fCommandFactory.createMITargetSelectCore(fCommandControl.getContext(), newCoreFile), + new DataRequestMonitor(getExecutor(), requestMonitor)); + } else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) { + IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class); + if (traceControl != null) { + ITraceTargetDMContext targetDmc = DMContexts.getAncestorOfType(fCommandControl.getContext(), ITraceTargetDMContext.class); + traceControl.loadTraceData(targetDmc, newCoreFile, requestMonitor); + } else { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Tracing not supported", null)); + requestMonitor.done(); + } + } else { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Invalid post-mortem type", null)); + requestMonitor.done(); + } } } }).schedule(); } else { - fCommandControl.queueCommand( - fCommandFactory.createMITargetSelectCore(fCommandControl.getContext(), coreFile), - new DataRequestMonitor(getExecutor(), requestMonitor)); + if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_CORE_FILE)) { + fCommandControl.queueCommand( + fCommandFactory.createMITargetSelectCore(fCommandControl.getContext(), coreFile), + new DataRequestMonitor(getExecutor(), requestMonitor)); + } else if (coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE)) { + IGDBTraceControl traceControl = fTracker.getService(IGDBTraceControl.class); + if (traceControl != null) { + ITraceTargetDMContext targetDmc = DMContexts.getAncestorOfType(fCommandControl.getContext(), ITraceTargetDMContext.class); + traceControl.loadTraceData(targetDmc, coreFile, requestMonitor); + } else { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Tracing not supported", null)); + requestMonitor.done(); + } + } else { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Invalid post-mortem type", null)); + requestMonitor.done(); + } } } catch (CoreException e) { - requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get core file path", e)); //$NON-NLS-1$ + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get post mortem file path", e)); requestMonitor.done(); } } else { diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunchDelegate.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunchDelegate.java index afcc8830d98..5a2598643dc 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunchDelegate.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunchDelegate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 QNX Software Systems and others. + * Copyright (c) 2008, 2010 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,6 +10,7 @@ * Windriver and Ericsson - Updated for DSF * IBM Corporation * Ericsson - Added support for Mac OS + * Ericsson - Added support for post-mortem trace files *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.launching; @@ -57,7 +58,10 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate2 private final static String NON_STOP_FIRST_VERSION = "6.8.50"; //$NON-NLS-1$ private boolean isNonStopSession = false; - + + private final static String TRACING_FIRST_VERSION = "7.1.50"; //$NON-NLS-1$ + private boolean fIsPostMortemTracingSession; + @Override public void launch( ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor ) throws CoreException { org.eclipse.cdt.launch.LaunchUtils.enableActivity("org.eclipse.cdt.debug.dsfgdbActivity", true); //$NON-NLS-1$ @@ -129,6 +133,10 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate2 throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Non-stop mode is only supported starting with GDB " + NON_STOP_FIRST_VERSION, null)); //$NON-NLS-1$ } + if (fIsPostMortemTracingSession && !isPostMortemTracingSupported(gdbVersion)) { + throw new DebugException(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Post-mortem tracing is only supported starting with GDB " + TRACING_FIRST_VERSION, null)); //$NON-NLS-1$ + } + launch.setServiceFactory(newServiceFactory(gdbVersion)); // Create and invoke the launch sequence to create the debug control and services @@ -254,6 +262,18 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate2 return false; } + private boolean isPostMortemTracingSession(ILaunchConfiguration config) { + SessionType sessionType = LaunchUtils.getSessionType(config); + if (sessionType == SessionType.CORE) { + try { + String coreType = config.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE, + IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT); + return coreType.equals(IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TRACE_FILE); + } catch (CoreException e) { + } + } + return false; + } @Override public boolean preLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor) throws CoreException { @@ -271,6 +291,7 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate2 // the source lookup adapter. isNonStopSession = isNonStopSession(configuration); + fIsPostMortemTracingSession = isPostMortemTracingSession(configuration); GdbLaunch launch = new GdbLaunch(configuration, mode, null); launch.initialize(); @@ -300,7 +321,22 @@ public class GdbLaunchDelegate extends AbstractCLaunchDelegate2 } return false; } - + + private boolean isPostMortemTracingSupported(String version) { + if (version.contains(LaunchUtils.MACOS_GDB_MARKER)) { + // Mac OS's GDB does not support post-mortem tracing + return false; + } + + if (TRACING_FIRST_VERSION.compareTo(version) <= 0 + // This feature will be available for GDB 7.2. But until that GDB is itself available + // there is a pre-release that has a version of 6.8.50.20090414 + || "6.8.50.20090414".equals(version)) { + return true; + } + return false; + } + // A subclass can override this method and provide its own ServiceFactory. protected IDsfDebugServicesFactory newServiceFactory(String version) { diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchMessages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchMessages.properties index 5b2c6800c2e..10ab61c6060 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchMessages.properties +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/LaunchMessages.properties @@ -86,16 +86,23 @@ CMainTab.Project_not_specified=Project not specified CMainTab.Program_not_specified=Program not specified CMainTab.Project_must_be_opened=Project must be opened CMainTab.Program_does_not_exist=Program does not exist -CMainTab.Core_does_not_exist=Core file does not exist +CMainTab.File_does_not_exist=File does not exist CMainTab.Main=Main CMainTab.&ProjectColon=&Project: CMainTab.C/C++_Application=C/C++ Application: +CMainTab.CoreFile_type=Core file +CMainTab.TraceFile_type=Trace file CMainTab.CoreFile_path=Core file (leave blank to trigger prompt): +CMainTab.TraceFile_path=Trace data file (leave blank to trigger prompt): CMainTab.Search...=Searc&h Project... CMainTab.Choose_program_to_run=Choose a &program to run: CMainTab.Choose_program_to_run_from_NAME=Choose a program to run from {0}: CMainTab.UseTerminal=Connect process input && output to a terminal. CMainTab.Program_is_not_a_recongnized_executable=Program is not a recognized executable. +CMaintab.Application_Selection=Application Selection +CMaintab.Core_Selection=Core File Selection +CMaintab.Trace_Selection=Trace File Selection +CMainTab.Post_mortem_file_type=Post Mortem file type: CDebuggerTab.Advanced_Options_Dialog_Title=Advanced Options CDebuggerTab.Stop_at_main_on_startup=Stop on startup at: diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java index a05eae80b00..87aa1541208 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java @@ -782,6 +782,18 @@ public class GDBProcesses_7_0 extends AbstractDsfService } private IMIContainerDMContext[] makeContainerDMCs(ICommandControlDMContext controlDmc, IThreadGroupInfo[] groups) { + // This is a workaround for post-mortem tracing because the early GDB release + // does not report a process when we do -list-thread-group + // GDB 7.2 will properly report the process so this + // code can be removed when GDB 7.2 is released + // START OF WORKAROUND + if (groups.length == 0 && fBackend.getSessionType() == SessionType.CORE) { + String groupId = MIProcesses.UNIQUE_GROUP_ID; + IProcessDMContext processDmc = createProcessContext(controlDmc, groupId); + return new IMIContainerDMContext[] {createContainerContext(processDmc, groupId)}; + } + // END OF WORKAROUND to be removed when GDB 7.2 is available + IMIContainerDMContext[] containerDmcs = new IMIContainerDMContext[groups.length]; for (int i = 0; i < groups.length; i++) { String groupId = groups[i].getGroupId(); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0.java index 867b1a181c7..0b12013f431 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0.java @@ -31,6 +31,7 @@ import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.debug.service.command.ICommand; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.IMIProcesses; @@ -80,6 +81,14 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro private boolean fReverseSupported = true; private boolean fReverseStepping = false; private boolean fReverseModeEnabled = false; + + /** + * This variable allows us to know if run control operation + * should be enabled or disabled. Run control operations are + * always enabled except when dealing with post-mortem debug + * session, or when visualizing tracepoints. + */ + private boolean fRunControlOperationsEnabled = true; private RunToLineActiveOperation fRunToLineActiveOperation = null; @@ -105,6 +114,7 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro if (fGdb.getSessionType() == SessionType.CORE) { // No execution for core files, so no support for reverse + fRunControlOperationsEnabled = false; fReverseSupported = false; } @@ -176,7 +186,7 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro */ @Override public void canResume(IExecutionDMContext context, DataRequestMonitor rm) { - if (fGdb.getSessionType() == SessionType.CORE) { + if (fRunControlOperationsEnabled == false) { rm.setData(false); rm.done(); return; @@ -189,7 +199,7 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro */ @Override public void canSuspend(IExecutionDMContext context, DataRequestMonitor rm) { - if (fGdb.getSessionType() == SessionType.CORE) { + if (fRunControlOperationsEnabled == false) { rm.setData(false); rm.done(); return; @@ -202,7 +212,7 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro */ @Override public void canStep(final IExecutionDMContext context, StepType stepType, final DataRequestMonitor rm) { - if (fGdb.getSessionType() == SessionType.CORE) { + if (fRunControlOperationsEnabled == false) { rm.setData(false); rm.done(); return; @@ -591,6 +601,16 @@ public class GDBRunControl_7_0 extends MIRunControl implements IReverseRunContro super.eventDispatched(e); } + + /** + * @since 3.0 + */ + @DsfServiceEventHandler + public void eventDispatched(ITraceRecordSelectedChangedDMEvent e) { + // We have started looking at trace records. We can no longer + // do run control operations. + fRunControlOperationsEnabled = false; + } /** @since 2.0 */ public void setReverseModeEnabled(boolean enabled) { diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java index 08d70369be1..721434516c9 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java @@ -43,6 +43,7 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommand; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.internal.service.command.events.MITracepointSelectedEvent; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; @@ -141,6 +142,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo public StateChangeReason getReason() { if (getMIEvent() instanceof MICatchpointHitEvent) { // must precede MIBreakpointHitEvent return StateChangeReason.EVENT_BREAKPOINT; + } else if (getMIEvent() instanceof MITracepointSelectedEvent) { // must precede MIBreakpointHitEvent + return StateChangeReason.UNKNOWN; // Don't display anything here, the details will take care of it } else if (getMIEvent() instanceof MIBreakpointHitEvent) { return StateChangeReason.BREAKPOINT; } else if (getMIEvent() instanceof MISteppingRangeEvent) { @@ -162,6 +165,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo MIStoppedEvent event = getMIEvent(); if (event instanceof MICatchpointHitEvent) { // must precede MIBreakpointHitEvent return ((MICatchpointHitEvent)event).getReason(); + } else if (event instanceof MITracepointSelectedEvent) { // must precede MIBreakpointHitEvent + return ((MITracepointSelectedEvent)event).getReason(); } else if (event instanceof MISharedLibEvent) { return ((MISharedLibEvent)event).getLibrary(); } else if (event instanceof MISignalEvent) { diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBTraceControl_7_1.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBTraceControl_7_2.java similarity index 51% rename from dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBTraceControl_7_1.java rename to dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBTraceControl_7_2.java index 5803f344310..c9ed8d02e2f 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBTraceControl_7_1.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBTraceControl_7_2.java @@ -13,20 +13,31 @@ package org.eclipse.cdt.dsf.gdb.service; import java.util.Hashtable; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.Immutable; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; +import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.ICachingService; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.cdt.dsf.debug.service.command.CommandCache; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.internal.service.command.events.MITracepointSelectedEvent; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; +import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; +import org.eclipse.cdt.dsf.mi.service.command.events.MIEvent; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIResultRecord; +import org.eclipse.cdt.dsf.mi.service.command.output.MITraceFindInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MITraceListVariablesInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MITraceListVariablesInfo.MITraceVariableInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MITraceStatusInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MITraceStopInfo; -import org.eclipse.cdt.dsf.mi.service.command.output.MITraceListVariablesInfo.MITraceVariableInfo; import org.eclipse.cdt.dsf.service.AbstractDsfService; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.IStatus; @@ -35,119 +46,104 @@ import org.eclipse.debug.core.ILaunchConfiguration; import org.osgi.framework.BundleContext; /** - * This class implements the ITraceControl interface which gives access + * This class implements the IGDBTraceControl interface which gives access * to the debugger's tracing functionality. * * @since 3.0 */ -public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTraceControl, ICachingService { +public class GDBTraceControl_7_2 extends AbstractDsfService implements IGDBTraceControl, ICachingService { -// @Immutable -// private static final class MITraceRecordDMContext extends AbstractDMContext implements ITraceRecordDMContext { -// -// // The trace record reference -// private final int fReference; -// -// /** -// * @param session the DsfSession for this service -// * @param parents the parent contexts -// * @param reference the trace record reference -// */ -// public MITraceRecordDMContext(DsfSession session, IDMContext[] parents, int reference) { -// super(session.getId(), parents); -// fReference = reference; -// } -// -// public int getReference() { -// return fReference; -// } -// -// /* (non-Javadoc) -// * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#equals(java.lang.Object) -// */ -// @Override -// public boolean equals(Object obj) { -// return baseEquals(obj) && (fReference == ((MITraceRecordDMContext) obj).fReference); -// } -// -// /* (non-Javadoc) -// * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#hashCode() -// */ -// @Override -// public int hashCode() { -// return baseHashCode() + fReference; -// } -// -// /* (non-Javadoc) -// * @see java.lang.Object#toString() -// */ -// @Override -// public String toString() { -// return baseToString() + ".reference(" + fReference + ")"; //$NON-NLS-1$//$NON-NLS-2$ -// } -// } -// -// /** -// * Trace record context used to indicate that there is no current trace record selected. -// */ -// @Immutable -// private static final class InvalidTraceRecordDMContext extends AbstractDMContext implements ITraceRecordDMContext { -// -// /** -// * @param session the DsfSession for this service -// * @param parents the parent contexts -// * @param reference the trace record reference -// */ -// public InvalidTraceRecordDMContext(DsfSession session, IDMContext[] parents) { -// super(session.getId(), parents); -// } -// -// -// /* (non-Javadoc) -// * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#equals(java.lang.Object) -// */ -// @Override -// public boolean equals(Object obj) { -// return baseEquals(obj); -// } -// -// /* (non-Javadoc) -// * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#hashCode() -// */ -// @Override -// public int hashCode() { -// return baseHashCode(); -// } -// -// /* (non-Javadoc) -// * @see java.lang.Object#toString() -// */ -// @Override -// public String toString() { -// return baseToString() + ".noTraceRecord"; //$NON-NLS-1$ -// } -// } -// -// @Immutable -// private static class MITraceRecordDMData implements ITraceRecordDMData { -// private final String fData; -// -// public MITraceRecordDMData(String data) { -// fData = data; -// } -// -// public String getData() { return fData; } -// } + @Immutable + protected static final class MITraceRecordDMContext extends AbstractDMContext implements ITraceRecordDMContext { + + // The trace record reference + private final int fReference; + + /** + * @param session the DsfSession for this service + * @param parents the parent contexts + * @param reference the trace record reference + */ + public MITraceRecordDMContext(DsfSession session, ITraceTargetDMContext parent, int reference) { + super(session.getId(), new IDMContext[] { parent }); + fReference = reference; + } + + public int getReference() { + return fReference; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + return baseEquals(obj) && (fReference == ((MITraceRecordDMContext) obj).fReference); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#hashCode() + */ + @Override + public int hashCode() { + return baseHashCode() + fReference; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return baseToString() + ".reference(" + fReference + ")"; //$NON-NLS-1$//$NON-NLS-2$ + } + } + + /** + * Trace record context used to indicate that there is no current trace record selected. + */ + @Immutable + protected static final class InvalidTraceRecordDMContext extends AbstractDMContext implements ITraceRecordDMContext { + + /** + * @param session the DsfSession for this service + * @param parents the parent contexts + * @param reference the trace record reference + */ + public InvalidTraceRecordDMContext(DsfSession session, ITraceTargetDMContext parent) { + super(session.getId(), new IDMContext[] { parent }); + } + + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + return baseEquals(obj); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#hashCode() + */ + @Override + public int hashCode() { + return baseHashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return baseToString() + ".noTraceRecord"; //$NON-NLS-1$ + } + } private class TraceVariableDMData implements ITraceVariableDMData { private String fName; private String fValue; private String fInitialValue; - public TraceVariableDMData(String name, String value) { - this(name, value, null); - } - public TraceVariableDMData(String name, String initial, String value) { fName = name; fInitialValue = initial; @@ -245,6 +241,20 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace return "\nTracing is not supported\n"; } + if (fBackend.getSessionType() == SessionType.CORE) { + str += "Off-line trace visualization\n"; + } else { + str += "Tracing with live execution\n"; + } + + if (fCurrentRecordDmc instanceof MITraceRecordDMContext) { + str += "Looking at trace frame " + + ((MITraceRecordDMContext)fCurrentRecordDmc).getReference() + + ", tracepoint " + fTracepointIndexForTraceRecord + "\n\n"; + } else { + str += "Not currently looking at any trace frame\n\n"; + } + str += "Tracing is currently" + (!fTracingActive ? " not":"") + " active\n"; str += "Buffer contains " + fNumberOfCollectedFrames + " trace frame" + (fNumberOfCollectedFrames>1?"s":"") + "\n";//" (out of ? created in total)\n"; @@ -270,7 +280,10 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace } else { str += " unknow reason"; } + str += "\n"; } + + return str; } @@ -304,25 +317,27 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace } } -// private static class TraceRecordSelectedChangedEvent extends AbstractDMEvent -// implements ITraceRecordSelectedChangedDMEvent { -// public TraceRecordSelectedChangedEvent(ITraceRecordDMContext context) { -// super(context); -// } -// } + public static class TraceRecordSelectedChangedEvent extends AbstractDMEvent + implements ITraceRecordSelectedChangedDMEvent { + public TraceRecordSelectedChangedEvent(ITraceRecordDMContext context) { + super(context); + } + } private CommandCache fTraceCache; private ICommandControlService fConnection; private CommandFactory fCommandFactory; - -// private ITraceRecordDMContext fCurrentRecordDmc = null; - - private boolean fIsTracingActive = false; - private boolean fIsTracingSupported = false; - private int fTraceRecordsStored = 0; + private IGDBBackend fBackend; + private ITraceRecordDMContext fCurrentRecordDmc; + private int fTracepointIndexForTraceRecord; - public GDBTraceControl_7_1(DsfSession session, ILaunchConfiguration config) { + private boolean fIsTracingActive; + private boolean fIsTracingCurrentlySupported; + private boolean fIsTracingFeatureAvailable = true; + private int fTraceRecordsStored; + + public GDBTraceControl_7_2(DsfSession session, ILaunchConfiguration config) { super(session); } @@ -351,10 +366,6 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace * initialization is done. */ private void doInitialize(RequestMonitor requestMonitor) { - - // Register to receive service events for this session. -// getSession().addServiceEventListener(this, null); - // Register this service. register(new String[] {IGDBTraceControl.class.getName()}, new Hashtable()); @@ -364,6 +375,7 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace fTraceCache = new CommandCache(getSession(), fConnection); fTraceCache.setContextAvailable(fConnection.getContext(), true); + fBackend = getServicesTracker().getService(IGDBBackend.class); fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); requestMonitor.done(); @@ -379,7 +391,6 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace @Override public void shutdown(RequestMonitor requestMonitor) { unregister(); -// getSession().removeServiceEventListener(this); super.shutdown(requestMonitor); } @@ -397,8 +408,27 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace rm.done(); return; } + + if (fIsTracingCurrentlySupported == false) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Tracing not supported", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + if (fBackend.getSessionType() == SessionType.CORE) { + rm.setData(false); + rm.done(); + return; + } + + if (fCurrentRecordDmc != null) { + // We are visualizing data, no more tracing possible. + rm.setData(false); + rm.done(); + return; + } - rm.setData(fIsTracingSupported); + rm.setData(true); rm.done(); } @@ -438,6 +468,25 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace rm.done(); return; } + + if (fIsTracingCurrentlySupported == false) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Tracing not supported", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + if (fBackend.getSessionType() == SessionType.CORE) { + rm.setData(false); + rm.done(); + return; + } + + if (fCurrentRecordDmc != null) { + // We are visualizing data, no more tracing possible. + rm.setData(false); + rm.done(); + return; + } isTracing(context, rm); } @@ -488,11 +537,17 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace return; } + if (fBackend.getSessionType() == SessionType.CORE) { + rm.setData(false); + rm.done(); + return; + } + // Although tracing can be automatically stopped on the target, we // don't go to the backend for this call, or we would make too many calls // Instead, we can use our buffered state; we simply won't know about an // automatic stop until a forced refresh. (Note that the MI notification - // about automatic stops, is not available until GDB 7.1 is released) + // about automatic stops, is not available until GDB 7.2 is released) rm.setData(fIsTracingActive); rm.done(); } @@ -503,21 +558,45 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace rm.done(); return; } + + if (fIsTracingCurrentlySupported == false) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Tracing not supported", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + if (fBackend.getSessionType() == SessionType.CORE) { + rm.setData(false); + rm.done(); + return; + } rm.setData(fTraceRecordsStored > 0); rm.done(); } - public void saveTraceData(ITraceTargetDMContext context, String file, boolean remoteSave, RequestMonitor rm) { + public void saveTraceData(final ITraceTargetDMContext context, final String file, + final boolean remoteSave, final RequestMonitor rm) { if (context == null) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Invalid context", null)); //$NON-NLS-1$ rm.done(); return; } - fConnection.queueCommand( - fCommandFactory.createMITraceSave(context, file, remoteSave), - new DataRequestMonitor(getExecutor(), rm)); + canSaveTraceData(context, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (!getData()) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot save trace data", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + fConnection.queueCommand( + fCommandFactory.createMITraceSave(context, file, remoteSave), + new DataRequestMonitor(getExecutor(), rm)); + } + }); } public void canLoadTraceData(ITraceTargetDMContext context, DataRequestMonitor rm) { @@ -527,20 +606,44 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace return; } + // If this service has been instantiated, it means we support loading trace data. + // Unlike the other operations, loading trace data does not require any GDB special state + // (like being connected to a target) rm.setData(true); rm.done(); } - public void loadTraceData(ITraceTargetDMContext context, String file, RequestMonitor rm) { + public void loadTraceData(final ITraceTargetDMContext context, final String file, final RequestMonitor rm) { if (context == null) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Invalid context", null)); //$NON-NLS-1$ rm.done(); return; } - fConnection.queueCommand( - fCommandFactory.createMITargetSelectTFile(context, file), - new DataRequestMonitor(getExecutor(), rm)); + canLoadTraceData(context, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (!getData()) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot load trace data", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + fConnection.queueCommand( + fCommandFactory.createMITargetSelectTFile(context, file), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + fIsTracingCurrentlySupported = true; + // Workaround for GDB pre-release where we don't get the details + // of the frame when we load a trace file. + // To get around this, we can force a select of record 0 + ITraceRecordDMContext initialRecord = createTraceRecordContext(context, 0); + selectTraceRecord(initialRecord, rm); + } + }); + } + }); } public void getTraceStatus(final ITraceTargetDMContext context, final DataRequestMonitor rm) { @@ -550,19 +653,31 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace return; } + if (fIsTracingFeatureAvailable == false) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Tracing not supported", null)); //$NON-NLS-1$ + rm.done(); + return; + } + fConnection.queueCommand( fCommandFactory.createMITraceStatus(context), new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleError() { + // The MI command + fIsTracingFeatureAvailable = false; + super.handleError(); + } @Override protected void handleSuccess() { MITraceStatusInfo info = getData(); - if (fIsTracingSupported != info.isTracingSupported()) { - fIsTracingSupported = info.isTracingSupported(); - getSession().dispatchEvent(new TracingSupportedChangeEvent(context, fIsTracingSupported), getProperties()); + if (fIsTracingCurrentlySupported != info.isTracingSupported()) { + fIsTracingCurrentlySupported = info.isTracingSupported(); + getSession().dispatchEvent(new TracingSupportedChangeEvent(context, fIsTracingCurrentlySupported), getProperties()); } - if (fIsTracingSupported) { + if (fIsTracingCurrentlySupported) { // Update the tracing state in case it was stopped by the backend if (fIsTracingActive != info.isTracingActive()) { fIsTracingActive = info.isTracingActive(); @@ -609,6 +724,12 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace return; } + if (fIsTracingCurrentlySupported == false) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Tracing not supported", null)); //$NON-NLS-1$ + rm.done(); + return; + } + if (varValue == null) { fConnection.queueCommand( fCommandFactory.createMITraceDefineVariable(context, varName), @@ -628,6 +749,12 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace return; } + if (fIsTracingCurrentlySupported == false) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Tracing not supported", null)); //$NON-NLS-1$ + rm.done(); + return; + } + // It may be possible to cache this call, if we can figure out that all the cases // where to data can change, to clear the cache in those cases fConnection.queueCommand( @@ -648,125 +775,173 @@ public class GDBTraceControl_7_1 extends AbstractDsfService implements IGDBTrace } }); } -// -// /** -// * Create a trace record context -// */ -// public ITraceRecordDMContext createTraceRecordContext(IDMContext ctx, int index) { -// return new MITraceRecordDMContext(getSession(), new IDMContext[] { ctx }, index); -// } -// -// public ITraceRecordDMContext createNextRecordContext(ITraceRecordDMContext ctx) { -// if (ctx instanceof InvalidTraceRecordDMContext) { -// // No specified context, so we return the first record context -// return new MITraceRecordDMContext(getSession(), new IDMContext[] { ctx }, 0); -// } -// if (ctx instanceof MITraceRecordDMContext) { -// return new MITraceRecordDMContext(getSession(), -// ctx.getParents(), -// ((MITraceRecordDMContext)ctx).getReference() + 1); -// } -// return null; -// } -// -// public ITraceRecordDMContext createPrevRecordContext(ITraceRecordDMContext ctx) { -// if (ctx instanceof MITraceRecordDMContext) { -// return new MITraceRecordDMContext(getSession(), -// ctx.getParents(), -// ((MITraceRecordDMContext)ctx).getReference() - 1); -// } -// return null; -// } -// -// -// public void getCurrentTraceRecordContext(ITraceTargetDMContext context, DataRequestMonitor drm) { -// if (fCurrentRecordDmc == null) { -// drm.setData(new InvalidTraceRecordDMContext(getSession(), new IDMContext[] { context })); -// } else { -// drm.setData(fCurrentRecordDmc); -// } -// drm.done(); -// } -// -// public void selectTraceRecord(final ITraceRecordDMContext context, final RequestMonitor rm) { -// if (context instanceof MITraceRecordDMContext) { -// ITraceTargetDMContext targetDmc = DMContexts.getAncestorOfType(context, ITraceTargetDMContext.class); -// fConnection.queueCommand( -// new MITraceFind(targetDmc, ((MITraceRecordDMContext)context).getReference()), -// new DataRequestMonitor(getExecutor(), rm) { -// @Override -// protected void handleSuccess() { -// if (getData().isFound() == false) { -// rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Could not find trace record", null)); //$NON-NLS-1$ -// } else { -// fCurrentRecordDmc = context; -// getSession().dispatchEvent(new TraceRecordSelectedChangedEvent(context), getProperties()); -// } -// rm.done(); -// } -// }); -// } else { -// rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid trace record context.", null)); //$NON-NLS-1$ -// rm.done(); -// } -// } -// -// public void setDefaultCollect(ITraceTargetDMContext context, String[] expressions, RequestMonitor rm) { -// fConnection.queueCommand( -// new MIGDBSetDefaultCollect(context, expressions), -// new DataRequestMonitor(getExecutor(), rm)); -// } -// -// public void getDefaultCollect(ITraceTargetDMContext context, final DataRequestMonitor rm) { -// // should use a cache and have it reset in setDefaultCommands -// fConnection.queueCommand( -// new MIGDBShowDefaultCollect(context), -// new DataRequestMonitor(getExecutor(), rm) { -// @Override -// protected void handleSuccess() { -// rm.setData(getData().getValue()); -// rm.done(); -// } -// }); -// } -// -// -// public void getTraceRecordData(ITraceRecordDMContext context, -// DataRequestMonitor rm) { -// assert false; -// } -// -// public void saveTracepoints(ITraceTargetDMContext context, -// String file, -// RequestMonitor rm) { -// assert false; -// } -// -// public void loadTracepoints(ITraceTargetDMContext context, -// String file, -// RequestMonitor rm) { -// assert false; -// } -// -// public void saveTraceData(ITraceTargetDMContext context, -// String file, -// RequestMonitor rm) { -// assert false; -// } -// -// public void loadTraceData(ITraceTargetDMContext context, -// String file, -// RequestMonitor rm) { -// assert false; -// } -// -// public void createTraceVariable(IExecutionDMContext context, -// RequestMonitor rm) { -// assert false; -// } + + /** + * Create a trace record context + */ + public ITraceRecordDMContext createTraceRecordContext(ITraceTargetDMContext ctx, int index) { + return new MITraceRecordDMContext(getSession(), ctx, index); + } + public ITraceRecordDMContext createNextRecordContext(ITraceRecordDMContext ctx) { + ITraceTargetDMContext targetDmc = DMContexts.getAncestorOfType(ctx, ITraceTargetDMContext.class); + if (ctx instanceof InvalidTraceRecordDMContext) { + // No specified context, so we return the context for the first + return new MITraceRecordDMContext(getSession(), targetDmc, 0); + } + if (ctx instanceof MITraceRecordDMContext) { + int recordIndex = ((MITraceRecordDMContext)ctx).getReference(); + recordIndex++; + if (recordIndex == fTraceRecordsStored) { + // Loop back to the front + recordIndex = 0; + } + return new MITraceRecordDMContext(getSession(), + targetDmc, + recordIndex); + } + return null; + } + + public ITraceRecordDMContext createPrevRecordContext(ITraceRecordDMContext ctx) { + if (ctx instanceof MITraceRecordDMContext) { + ITraceTargetDMContext targetDmc = DMContexts.getAncestorOfType(ctx, ITraceTargetDMContext.class); + int recordIndex = ((MITraceRecordDMContext)ctx).getReference(); + if (recordIndex == 0) { + // Loop back to the end + recordIndex = fTraceRecordsStored; // The last index of a trace record (zero-based) + } + recordIndex--; + return new MITraceRecordDMContext(getSession(), + targetDmc, + recordIndex); + } + return null; + } + + + public void getCurrentTraceRecordContext(ITraceTargetDMContext context, DataRequestMonitor drm) { + if (fCurrentRecordDmc == null) { + drm.setData(new InvalidTraceRecordDMContext(getSession(), context)); + } else { + drm.setData(fCurrentRecordDmc); + } + drm.done(); + } + + public void selectTraceRecord(final ITraceRecordDMContext context, final RequestMonitor rm) { + if (fIsTracingCurrentlySupported == false) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Tracing not supported", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + if (context instanceof MITraceRecordDMContext) { + ITraceTargetDMContext targetDmc = DMContexts.getAncestorOfType(context, ITraceTargetDMContext.class); + fConnection.queueCommand( + fCommandFactory.createMITraceFind(targetDmc, ((MITraceRecordDMContext)context).getReference()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (getData().isFound() == false) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Could not find trace record", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + fCurrentRecordDmc = context; + fTracepointIndexForTraceRecord = getData().getTraceRecord().getTracepointId(); + + // This event will indicate to the other services that we are visualizing trace data. + getSession().dispatchEvent(new TraceRecordSelectedChangedEvent(context), getProperties()); + + // We could rely on the TraceRecordSelectedChangedEvent to update all the views, but this + // would require a lot of changes. + // Notice that looking at a new trace record should behave in the same manner + // as when the debugger suspends during normal execution; therefore we can simply + // trigger an MIStoppedEvent, as if reported by GDB. Note that we do this already for + // cases where GDB is missing such a event (like older versions of GDB when using a CLI command) + IMIProcesses procService = getServicesTracker().getService(IMIProcesses.class); + if (procService == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Could not find necessary services", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + final MIResultRecord rr = getData().getMIOutput().getMIResultRecord(); + if (rr == null) { + assert false; + rm.done(); + return; + } + + // First find the process we are using. + ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(context, ICommandControlDMContext.class); + procService.getProcessesBeingDebugged( + controlDmc, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + assert getData() != null; + assert getData().length == 1; + + if (getData() == null || getData().length < 1) { + rm.done(); + return; + } + + // Choose the first process for now, until gdb can tell + // us which process the trace record is associated with. + // Or maybe GDB already tells us by only reporting a single + // process? + IContainerDMContext processContainerDmc = (IContainerDMContext)(getData()[0]); + + // Now find the proper thread. We must do this hear because in post-mortem debugging + // we cannot rely on MIRunControl using 'thread', as it will fail + IMIProcesses procService = getServicesTracker().getService(IMIProcesses.class); + if (procService == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Could not find necessary services", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + procService.getProcessesBeingDebugged( + processContainerDmc, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + assert getData() != null; + assert getData().length == 1; + + if (getData() == null || getData().length < 1) { + rm.done(); + return; + } + + IExecutionDMContext execDmc = (IExecutionDMContext)getData()[0]; + MIEvent event = MITracepointSelectedEvent.parse(execDmc, rr.getToken(), rr.getMIResults()); + getSession().dispatchEvent(event, getProperties()); + + rm.done(); + } + }); + } + }); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid trace record context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + + public void getTraceRecordData(ITraceRecordDMContext context, DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Not implemented.", null)); //$NON-NLS-1$ + rm.done(); + } + public void flushCache(IDMContext context) { fTraceCache.reset(context); } - } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java index 6e968381582..c4d8515845c 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GdbDebugServicesFactory.java @@ -43,7 +43,8 @@ import org.eclipse.debug.core.ILaunchConfiguration; public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { // This should eventually be "7.0" once GDB 7.0 is released - private static final String GDB_7_0_VERSION = "6.8.50.20090218"; //$NON-NLS-1$ + private static final String GDB_7_0_VERSION = "6.8.50.20090218"; //$NON-NLS-1$ + private static final String GDB_7_2_VERSION = "7.1.50"; //$NON-NLS-1$ private final String fVersion; @@ -163,12 +164,15 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { /** @since 3.0 */ protected IGDBTraceControl createTraceControlService(DsfSession session, ILaunchConfiguration config) { - // This service is available for GDB 7.1. But until that GDB is itself available + // This service is available for GDB 7.2. But until that GDB is itself available // there is a pre-release that has a version of 6.8.50.20090414 - if ("6.8.50.20090414".compareTo(fVersion) <= 0) { - return new GDBTraceControl_7_1(session, config); + if (GDB_7_2_VERSION.compareTo(fVersion) <= 0 || "6.8.50.20090414".equals(fVersion)) { //$NON-NLS-1$ + return new GDBTraceControl_7_2(session, config); } - // There is no implementation of the TraceControl service before GDB 7.1 + // There is currently no implementation of the TraceControl service before GDB 7.2 + // It could be done with restricted functionality for GDB 7.1 and maybe even 7.0 + // but the service would have to be properly coded, as some MI commands don't exists + // in those older GDB versions. Also, gdbserver only supports tracing starting with 7.2 return null; } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBTraceControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBTraceControl.java index f4ed53870a9..729b9a2aeea 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBTraceControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBTraceControl.java @@ -22,6 +22,9 @@ import org.eclipse.cdt.dsf.service.IDsfService; * The TraceControl service provides access to the debugger Tracing functionality. * It is used to do such things as start and stop tracing. * + * As this functionality is very new to GDB itself, this interface is likely + * to change a little in the next release of CDT. + * * @since 3.0 */ public interface IGDBTraceControl extends IDsfService { @@ -98,41 +101,17 @@ public interface IGDBTraceControl extends IDsfService { * {@link saveTraceData} should have the correct format to be loaded by this call. */ public void loadTraceData(ITraceTargetDMContext context, - String file, - RequestMonitor rm); + String file, + RequestMonitor rm); -// /** -// * Request that the backend use the specified trace record. -// */ -// public void selectTraceRecord(ITraceRecordDMContext context, RequestMonitor rm); -// /** -// * Returns the trace record data of the specified trace record. -// */ -// public void getTraceRecordData(ITraceRecordDMContext context, -// DataRequestMonitor rm); -// -// /** -// * Save all tracepoint definitions to the specified file in a -// * format suitable for {@link loadTracepoints}. -// */ -// // This should probably be part of the GDB Breakpoints service -// public void saveTracepoints(ITraceTargetDMContext context, -// String file, -// RequestMonitor rm); -// -// /** -// * Load all tracepoint definitions from the specified file. -// * A file created from a call to {@link saveTracepoints} should have -// * the correct format to be loaded by this call. -// */ -// // This should probably be part of the GDB Breakpoints service -// public void loadTracepoints(ITraceTargetDMContext context, -// String file, -// RequestMonitor rm); -// - + /** + * Request that the backend use the specified trace record. + */ + public void selectTraceRecord(ITraceRecordDMContext context, RequestMonitor rm); + public void getTraceRecordData(ITraceRecordDMContext context, DataRequestMonitor rm); + ///////////////////////////////////////////////// // GDB specific part ///////////////////////////////////////////////// @@ -179,12 +158,8 @@ public interface IGDBTraceControl extends IDsfService { */ public void getTraceVariables(ITraceTargetDMContext context, DataRequestMonitor rm); -// public ITraceRecordDMContext createTraceRecordContext(IDMContext ctx, int index); -// public void getCurrentTraceRecordContext(ITraceTargetDMContext context, DataRequestMonitor drm); -// public ITraceRecordDMContext createNextRecordContext(ITraceRecordDMContext ctx); -// public ITraceRecordDMContext createPrevRecordContext(ITraceRecordDMContext ctx); -// -// public void setDefaultCollect(ITraceTargetDMContext context, String[] expressions, RequestMonitor rm); -// public void getDefaultCollect(ITraceTargetDMContext context, DataRequestMonitor rm); - + public ITraceRecordDMContext createTraceRecordContext(ITraceTargetDMContext ctx, int index); + public void getCurrentTraceRecordContext(ITraceTargetDMContext context, DataRequestMonitor drm); + public ITraceRecordDMContext createNextRecordContext(ITraceRecordDMContext ctx); + public ITraceRecordDMContext createPrevRecordContext(ITraceRecordDMContext ctx); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java index 3e75f2e6e9f..cac06118c2d 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java @@ -40,6 +40,7 @@ import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; import org.eclipse.cdt.dsf.gdb.service.GDBRunControl_7_0; import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; import org.eclipse.cdt.dsf.gdb.service.IReverseRunControl; import org.eclipse.cdt.dsf.gdb.service.SessionType; import org.eclipse.cdt.dsf.gdb.service.GDBProcesses_7_0.ContainerExitedDMEvent; @@ -606,7 +607,18 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl { } } } - + + /** @since 3.0 */ + @DsfServiceEventHandler + public void eventDispatched(ITraceRecordSelectedChangedDMEvent e) { + // Once we start looking at trace frames, we should not use + // the --thread or --frame options because GDB does not handle + // it well, there are no actual threads running. + // We only need to do this once, but it won't hurt to do it + // every time. + setUseThreadAndFrameOptions(false); + } + public static class InitializationShutdownStep extends Sequence.Step { public enum Direction { INITIALIZING, SHUTTING_DOWN } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java index f07c1505345..66d2a8951d6 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java @@ -35,6 +35,7 @@ import org.eclipse.cdt.dsf.debug.service.command.CommandCache; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.gdb.GDBTypeParser.GDBType; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetAttributes; import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetChildCount; @@ -436,6 +437,12 @@ public class MIExpressions extends AbstractDsfService implements IExpressions, I private MIVariableManager varManager; private CommandFactory fCommandFactory; + /** + * Indicates that we are currently visualizing trace data. + * In this case, some errors should not be reported. + */ + private boolean fTraceVisualization; + public MIExpressions(DsfSession session) { super(session); } @@ -754,6 +761,15 @@ public class MIExpressions extends AbstractDsfService implements IExpressions, I rm.setData(new FormattedValueDMData(getData().getValue())); rm.done(); } + @Override + protected void handleError() { + if (fTraceVisualization) { + rm.setData(new FormattedValueDMData("")); //$NON-NLS-1$ + rm.done(); + } else { + super.handleError(); + } + } }); } else { fExpressionCache.execute( @@ -1004,6 +1020,14 @@ public class MIExpressions extends AbstractDsfService implements IExpressions, I // MIVariableManager separately traps this event } + /** @since 3.0 */ + @DsfServiceEventHandler + public void eventDispatched(ITraceRecordSelectedChangedDMEvent e) { + // Once we start looking at a trace record, we remain in + // trace visualization mode. + fTraceVisualization = true; + } + /** * {@inheritDoc} * @since 1.1 diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java index f849f6eba01..d34416a92c6 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java @@ -40,6 +40,7 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommand; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.internal.service.command.events.MITracepointSelectedEvent; import org.eclipse.cdt.dsf.mi.service.MIBreakpoints.MIBreakpointDMContext; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent; @@ -177,6 +178,8 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I public StateChangeReason getReason() { if (getMIEvent() instanceof MICatchpointHitEvent) { // must precede MIBreakpointHitEvent return StateChangeReason.EVENT_BREAKPOINT; + } else if (getMIEvent() instanceof MITracepointSelectedEvent) { // must precede MIBreakpointHitEvent + return StateChangeReason.UNKNOWN; // Don't display anything here, the details will take care of it } else if (getMIEvent() instanceof MIBreakpointHitEvent) { return StateChangeReason.BREAKPOINT; } else if (getMIEvent() instanceof MISteppingRangeEvent) { @@ -201,6 +204,8 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I MIStoppedEvent event = getMIEvent(); if (event instanceof MICatchpointHitEvent) { // must precede MIBreakpointHitEvent return ((MICatchpointHitEvent)event).getReason(); + } else if (event instanceof MITracepointSelectedEvent) { // must precede MIBreakpointHitEvent + return ((MITracepointSelectedEvent)event).getReason(); } else if (event instanceof MISharedLibEvent) { return ((MISharedLibEvent)event).getLibrary(); } else if (event instanceof MISignalEvent) { diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIStack.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIStack.java index c7386189512..ac72a824096 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIStack.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIStack.java @@ -26,16 +26,17 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.ICachingService; import org.eclipse.cdt.dsf.debug.service.IRunControl; -import org.eclipse.cdt.dsf.debug.service.IStack; import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent; import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent; import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.cdt.dsf.debug.service.IStack; import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl; import org.eclipse.cdt.dsf.debug.service.command.CommandCache; import org.eclipse.cdt.dsf.debug.service.command.ICommand; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; @@ -61,7 +62,6 @@ public class MIStack extends AbstractDsfService implements IFrameDMContext { private final int fLevel; - // public MIFrameDMC(MIStack service, int level) { public MIFrameDMC(String sessionId, IExecutionDMContext execDmc, int level) { super(sessionId, new IDMContext[] { execDmc }); fLevel = level; @@ -166,6 +166,12 @@ public class MIStack extends AbstractDsfService private MIStoppedEvent fCachedStoppedEvent; private IRunControl fRunControl; + /** + * Indicates that we are currently visualizing trace data. + * In this case, some errors should not be reported. + */ + private boolean fTraceVisualization; + public MIStack(DsfSession session) { super(session); @@ -250,20 +256,19 @@ public class MIStack extends AbstractDsfService final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); if (execDmc == null) { - //rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "No frame context found in " + ctx, null)); //$NON-NLS-1$ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context " + ctx, null)); //$NON-NLS-1$ rm.done(); return; } - // Make sure the thread is stopped - if (!fRunControl.isSuspended(execDmc)) { + // Make sure the thread is stopped but only if we are not visualizing trace data + if (!fTraceVisualization && !fRunControl.isSuspended(execDmc)) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Context is running: " + ctx, null)); //$NON-NLS-1$ rm.done(); return; } - if (startIndex == 0 && endIndex == 0) { + if (fTraceVisualization || (startIndex == 0 && endIndex == 0)) { // Try to retrieve the top stack frame from the cached stopped event. if (fCachedStoppedEvent != null && fCachedStoppedEvent.getFrame() != null && @@ -329,7 +334,6 @@ public class MIStack extends AbstractDsfService }); } - //private MIFrameDMC[] getFrames(DsfMIStackListFramesInfo info) { private IFrameDMContext[] getFrames(IMIExecutionDMContext execDmc, MIStackListFramesInfo info, int firstIndex, int lastIndex, int startIndex) { int length = info.getMIFrames().length; if (lastIndex > 0) { @@ -408,15 +412,15 @@ public class MIStack extends AbstractDsfService // Retrieve the top stack frame from the stopped event only if the selected thread is the one on which stopped event // is raised - if (fCachedStoppedEvent != null && - execDmc.equals(fCachedStoppedEvent.getDMContext()) && - miFrameDmc.fLevel == 0 && - fCachedStoppedEvent.getFrame() != null) - { - rm.setData(new FrameDataFromStoppedEvent(fCachedStoppedEvent)); - rm.done(); - return; - } + if (fTraceVisualization || miFrameDmc.fLevel == 0) { + if (fCachedStoppedEvent != null && fCachedStoppedEvent.getFrame() != null && + (execDmc.equals(fCachedStoppedEvent.getDMContext()) || fTraceVisualization)) + { + rm.setData(new FrameDataFromStoppedEvent(fCachedStoppedEvent)); + rm.done(); + return; + } + } // If not, retrieve the full list of frame data. class FrameDataFromMIStackFrameListInfo extends FrameData { @@ -475,13 +479,24 @@ public class MIStack extends AbstractDsfService return; } - // If not, retrieve the full list of frame data. + if (fTraceVisualization) { + // For the pre-release of GDB that supports tracepoints, we cannot ask + // for the list of arguments for all stack frames, but only for available + // ones. Again, I'm hoping that GDB 7.2 will be smarter than that. + getArgumentsForTraceVisualization(frameDmc, rm); + return; + } + + // If not, retrieve the full list of frame data. Although we only need one frame + // for this call, it will be stored the cache and made available for other calls. fMICommandCache.execute( // We don't actually need to ask for the values in this case, but since // we will ask for them right after, it is more efficient to ask for them now // so as to cache the result. If the command fails, then we will ask for // the result without the values - fCommandFactory.createMIStackListArguments(execDmc, true), + // Don't ask for value when we are visualizing trace data, since some + // data will not be there, and the command will fail + fCommandFactory.createMIStackListArguments(execDmc, true), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -504,8 +519,8 @@ public class MIStack extends AbstractDsfService @Override protected void handleError() { // If the command fails it can be because we asked for values. - // This can happen with uninitialized values and pretty printers (bug 307614) - // or when visualizing tracepoints. Since asking for values was simply an optimization + // This can happen with uninitialized values and pretty printers (bug 307614). + // Since asking for values was simply an optimization // to store the command in the cache, let's retry the command without asking for values. fMICommandCache.execute( fCommandFactory.createMIStackListArguments(execDmc, false), @@ -533,6 +548,43 @@ public class MIStack extends AbstractDsfService }); } + // For the pre-release of GDB that supports tracepoints, we cannot ask + // for the list of arguments for all stack frames, but only for available + // ones. Again, I'm hoping that GDB 7.2 will be smarter than that. + private void getArgumentsForTraceVisualization(final IFrameDMContext frameDmc, final DataRequestMonitor rm) { + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); + + getStackDepth(execDmc, 0, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + int bottomFrame = getData() - 1; + fMICommandCache.execute( + // Don't ask for values for tracepoints + fCommandFactory.createMIStackListArguments(execDmc, false, 0, bottomFrame), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Find the index to the correct MI frame object. + // Note: this is a short-cut, but it won't work once we implement retrieving + // partial lists of stack frames. + int idx = frameDmc.getLevel(); + if (idx == -1 || idx >= getData().getMIFrames().length) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Invalid frame " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create the variable array out of MIArg array. + MIArg[] args = getData().getMIFrames()[idx].getArgs(); + if (args == null) args = new MIArg[0]; + rm.setData(makeVariableDMCs(frameDmc, MIVariableDMC.Type.ARGUMENT, args.length)); + rm.done(); + } + }); + } + }); + } + public void getVariableData(IVariableDMContext variableDmc, final DataRequestMonitor rm) { if (!(variableDmc instanceof MIVariableDMC)) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context type " + variableDmc, null)); //$NON-NLS-1$ @@ -589,8 +641,13 @@ public class MIStack extends AbstractDsfService } if (miVariableDmc.fType == MIVariableDMC.Type.ARGUMENT){ + if (fTraceVisualization) { + getArgumentsDataForTraceVisualization(miVariableDmc, rm); + } else { fMICommandCache.execute( - fCommandFactory.createMIStackListArguments(execDmc, true), + // Don't ask for value when we are visualizing trace data, since some + // data will not be there, and the command will fail + fCommandFactory.createMIStackListArguments(execDmc, true), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -610,8 +667,7 @@ public class MIStack extends AbstractDsfService @Override protected void handleError() { // Unable to get the values. This can happen with uninitialized values and pretty printers (bug 307614) - // or when visualizing tracepoints. Either way, we try to ask for the arguments without their values, - // which is better than nothing + // Let's try to ask for the arguments without their values, which is better than nothing fMICommandCache.execute( fCommandFactory.createMIStackListArguments(execDmc, false), new DataRequestMonitor(getExecutor(), rm) { @@ -633,10 +689,13 @@ public class MIStack extends AbstractDsfService }); } }); + } }//if if (miVariableDmc.fType == MIVariableDMC.Type.LOCAL){ fMICommandCache.execute( - fCommandFactory.createMIStackListLocals(frameDmc, true), + // Don't ask for value when we are visualizing trace data, since some + // data will not be there, and the command will fail + fCommandFactory.createMIStackListLocals(frameDmc, !fTraceVisualization), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -652,9 +711,8 @@ public class MIStack extends AbstractDsfService } @Override protected void handleError() { - // Unable to get the value. This can happen with uninitialized values and pretty printers (bug 307614) - // or when visualizing tracepoints. Either way, we try to ask for the variables without their values, - // which is better than nothing + // Unable to get the value. This can happen with uninitialized values and pretty printers (bug 307614). + // Let's try to ask for the variables without their values, which is better than nothing fMICommandCache.execute( fCommandFactory.createMIStackListLocals(frameDmc, false), new DataRequestMonitor(getExecutor(), rm) { @@ -677,6 +735,52 @@ public class MIStack extends AbstractDsfService } + // For the pre-release of GDB that supports tracepoints, we cannot ask + // for the list of arguments for all stack frames, but only for available + // ones. Again, I'm hoping that GDB 7.2 will be smarter than that. + private void getArgumentsDataForTraceVisualization(final MIVariableDMC miVariableDmc, final DataRequestMonitor rm) { + final MIFrameDMC frameDmc = DMContexts.getAncestorOfType(miVariableDmc, MIFrameDMC.class); + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); + + class VariableData implements IVariableDMData { + private MIArg dsfMIArg; + VariableData(MIArg arg){ + dsfMIArg = arg; + } + public String getName() { return dsfMIArg.getName(); } + public String getValue() { return dsfMIArg.getValue(); } + @Override + public String toString() { return dsfMIArg.toString(); } + } + + getStackDepth(execDmc, 0, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + int bottomFrame = getData() - 1; + fMICommandCache.execute( + // Don't ask for values for tracepoints + fCommandFactory.createMIStackListArguments(execDmc, false, 0, bottomFrame), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Find the correct frame and argument + if ( frameDmc.fLevel >= getData().getMIFrames().length || + miVariableDmc.fIndex >= getData().getMIFrames()[frameDmc.fLevel].getArgs().length ) + { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid variable " + miVariableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create the data object. + rm.setData(new VariableData(getData().getMIFrames()[frameDmc.fLevel].getArgs()[miVariableDmc.fIndex])); + rm.done(); + } + }); + } + }); + } + private MIVariableDMC[] makeVariableDMCs(IFrameDMContext frame, MIVariableDMC.Type type, int count) { MIVariableDMC[] variables = new MIVariableDMC[count]; for (int i = 0; i < count; i++) { @@ -723,7 +827,9 @@ public class MIStack extends AbstractDsfService // we will ask for them right after, it is more efficient to ask for them now // so as to cache the result. If the command fails, then we will ask for // the result without the values - fCommandFactory.createMIStackListLocals(frameDmc, true), + // Don't ask for value when we are visualizing trace data, since some + // data will not be there, and the command will fail + fCommandFactory.createMIStackListLocals(frameDmc, !fTraceVisualization), new DataRequestMonitor(getExecutor(), countingRm) { @Override protected void handleSuccess() { @@ -734,8 +840,8 @@ public class MIStack extends AbstractDsfService @Override protected void handleError() { // If the command fails it can be because we asked for values. - // This can happen with uninitialized values and pretty printers (bug 307614) - // or when visualizing tracepoints. Since asking for values was simply an optimization + // This can happen with uninitialized values and pretty printers (bug 307614). + // Since asking for values was simply an optimization // to store the command in the cache, let's retry the command without asking for values. fMICommandCache.execute( fCommandFactory.createMIStackListLocals(frameDmc, false), @@ -755,7 +861,7 @@ public class MIStack extends AbstractDsfService final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(dmc, IMIExecutionDMContext.class); if (execDmc != null) { // Make sure the thread is stopped - if (!fRunControl.isSuspended(execDmc)) { + if (!fTraceVisualization && !fRunControl.isSuspended(execDmc)) { rm.setData(0); rm.done(); return; @@ -787,6 +893,25 @@ public class MIStack extends AbstractDsfService rm.setData(getData().getDepth()); rm.done(); } + @Override + protected void handleError() { + if (fTraceVisualization) { + // when visualizing trace data, the pre-release GDB, the command + // -stack-info-depth will return an error if we ask for any level + // that GDB does not know about. We would have to iteratively + // try different depths until we found the deepest that succeeds. + // That is too much of a hack for a pre-release. Let's hope + // GDB 7.2 will properly answer -stack-info-depth when visualizing + // trace data. Until then, we can safely say we have one stack + // frame, which is going to be the case for 95% of the cases. + // To have more stack frames, the user would have to have collected + // the registers and enough stack memory for GDB to build another frame. + rm.setData(1); + rm.done(); + } else { + super.handleError(); + } + } }); } else { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ @@ -833,6 +958,13 @@ public class MIStack extends AbstractDsfService } } + /** @since 3.0 */ + @DsfServiceEventHandler + public void eventDispatched(ITraceRecordSelectedChangedDMEvent e) { + // Once we start looking at a trace record, we remain in + // trace visualization mode. + fTraceVisualization = true; + } /** * {@inheritDoc} * @since 1.1 diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java index f75d68698b5..92a60e208a9 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java @@ -15,6 +15,7 @@ package org.eclipse.cdt.dsf.mi.service; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -26,25 +27,26 @@ import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.debug.service.IExpressions; -import org.eclipse.cdt.dsf.debug.service.IFormattedValues; -import org.eclipse.cdt.dsf.debug.service.IRunControl; -import org.eclipse.cdt.dsf.debug.service.IStack; import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.cdt.dsf.debug.service.IFormattedValues; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext; import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData; import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent; +import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.IStack; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.debug.service.command.ICommand; import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.debug.service.command.ICommandListener; import org.eclipse.cdt.dsf.debug.service.command.ICommandResult; import org.eclipse.cdt.dsf.debug.service.command.ICommandToken; import org.eclipse.cdt.dsf.debug.service.command.IEventListener; -import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.gdb.GDBTypeParser; import org.eclipse.cdt.dsf.gdb.GDBTypeParser.GDBType; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; import org.eclipse.cdt.dsf.mi.service.MIExpressions.ExpressionInfo; import org.eclipse.cdt.dsf.mi.service.MIExpressions.MIExpressionDMC; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; @@ -1505,7 +1507,7 @@ public class MIVariableManager implements ICommandControl { // The variable object is out-of-scope and we // should not use it. if (shouldCreateNew) { - /** + /* * It may happen that when accessing a varObject we find it to be * out-of-scope. The expression for which we are trying to access a varObject * could still be valid, and therefore we should try to create a new varObject for @@ -1850,4 +1852,22 @@ public class MIVariableManager implements ICommandControl { // The views will fully refresh on a MemoryChangedEvent markAllOutOfDate(); } + + /** + * @since 3.0 + */ + @DsfServiceEventHandler + public void eventDispatched(ITraceRecordSelectedChangedDMEvent e) { + // We have a big limitation with tracepoints! + // GDB usually only reports a depth of 1, for every trace record, no + // matter where it occurred. This means that our naming scheme for VariableObjectId + // fails miserably because all objects will have the same depth and we will confuse + // them. Until we find a good solution, we have to clear our entire list of + // of variable objects (and delete them in GDB to avoid having too many). + Iterator> iterator = lruVariableList.entrySet().iterator(); + while (iterator.hasNext()){ + iterator.next(); + iterator.remove(); + } + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/AbstractMIControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/AbstractMIControl.java index 0043a2a0bca..8ceb80ab33d 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/AbstractMIControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/AbstractMIControl.java @@ -80,7 +80,7 @@ public abstract class AbstractMIControl extends AbstractDsfService // MI did not always support the --thread/--frame options // This boolean is used to know if we should use -thread-select and -stack-select-frame instead - private final boolean fUseThreadAndFrameOptions; + private boolean fUseThreadAndFrameOptions; // currentStackLevel and currentThreadId are only necessary when // we must use -thread-select and -stack-select-frame private int fCurrentStackLevel = -1; @@ -157,6 +157,13 @@ public abstract class AbstractMIControl extends AbstractDsfService return fTracingStream; } + /** + * @since 3.0 + */ + protected void setUseThreadAndFrameOptions(boolean shouldUse) { + fUseThreadAndFrameOptions = shouldUse; + } + /** * @since 3.0 */ diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java index 530f67a6a9e..eaea22d5a23 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java @@ -105,6 +105,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIThreadInfo; import org.eclipse.cdt.dsf.mi.service.command.commands.MIThreadListIds; import org.eclipse.cdt.dsf.mi.service.command.commands.MIThreadSelect; import org.eclipse.cdt.dsf.mi.service.command.commands.MITraceDefineVariable; +import org.eclipse.cdt.dsf.mi.service.command.commands.MITraceFind; import org.eclipse.cdt.dsf.mi.service.command.commands.MITraceListVariables; import org.eclipse.cdt.dsf.mi.service.command.commands.MITraceSave; import org.eclipse.cdt.dsf.mi.service.command.commands.MITraceStart; @@ -145,6 +146,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIStackListFramesInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIStackListLocalsInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIThreadInfoInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIThreadListIdsInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MITraceFindInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MITraceListVariablesInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MITraceStatusInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MITraceStopInfo; @@ -660,6 +662,10 @@ public class CommandFactory { public ICommand createMITraceDefineVariable(ITraceTargetDMContext ctx, String varName, String varValue) { return new MITraceDefineVariable(ctx, varName, varValue); } + + public ICommand createMITraceFind(ITraceTargetDMContext ctx, int frameReference) { + return new MITraceFind(ctx, frameReference); + } public ICommand createMITraceListVariables(ITraceTargetDMContext ctx) { return new MITraceListVariables(ctx); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MITraceFind.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MITraceFind.java new file mode 100644 index 00000000000..d880a344ea9 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MITraceFind.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service.command.commands; + +import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext; +import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; +import org.eclipse.cdt.dsf.mi.service.command.output.MITraceFindInfo; + +/** + * -trace-find MODE [PARAMS...] + * + * Find a trace frame using criteria defined by MODE and PARAMS. The following + * lists permissible modes and their parameters. + * + * none - No parameters are required. Stops examining trace frames. + * frame-number - An integer is required as parameter. Selects tracepoint frame + * with that index. + * tracepoint-number - An integer is required as parameter. Finds next trace + * frame that corresponds to tracepoint with the specified number. + * pc - An integer address is required as parameter. Finds next trace + * frame that corresponds to any tracepoint at the specified address. + * pc-inside-range - Two integer addresses are required as parameters. Finds next + * trace frame that corresponds to a tracepoint at an address inside + * the specified range. + * pc-outside-range - Two integer addresses are required as parameters. Finds next + * trace frame that corresponds to a tracepoint at an address outside + * the specified range. + * line - Line specification is required as parameter. + * Finds next trace frame that corresponds to a tracepoint at the + * specified location. + * + * If the 'none' was passed as mode, the response does not have fields. Otherwise, the + * response may have the following fields: + * + * found - This field has either 0 or 1 as the value, depending on whether a matching + * tracepoint was found. + * traceframe - The index of the found traceframe. This field is present i f the 'found' + * field has value of 1. + * tracepoint - The index of the found tracepoint. This field is present if the 'found' + * field has value of 1. + * frame - The stack frame when the traceframe was collected + * + * @since 3.0 + */ +public class MITraceFind extends MICommand { + public MITraceFind(ITraceTargetDMContext ctx, int frameReference) { + super(ctx, "-trace-find", null, new String[] { "frame-number", Integer.toString(frameReference) }); //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + public MITraceFindInfo getResult(MIOutput out) { + return new MITraceFindInfo(out); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MITraceFindInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MITraceFindInfo.java new file mode 100644 index 00000000000..0e48736a6df --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MITraceFindInfo.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service.command.output; + + +/** + * -trace-find result. + * @since 3.0 + */ +public class MITraceFindInfo extends MIInfo { + + private boolean fFound; + private MITraceRecord fTraceRecord; + + public MITraceFindInfo(MIOutput out) { + super(out); + parse(); + } + + public boolean isFound() { + return fFound; + } + + public MITraceRecord getTraceRecord() { + return fTraceRecord; + } + + private void parse() { + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("found")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIConst) { + fFound = ((MIConst)val).getString().equals("0") ? false : true; //$NON-NLS-1$ + if (fFound) { + fTraceRecord = new MITraceRecord(getMIOutput()); + } + } + } + } + } + } + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MITraceRecord.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MITraceRecord.java new file mode 100644 index 00000000000..336f347f637 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MITraceRecord.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2010 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service.command.output; + + +/** + * -trace-find result. + * @since 3.0 + */ +public class MITraceRecord extends MIInfo { + + private MIFrame fStackFrame = null; + private Integer fTracepoint = null; + private Integer fRecordIndex = null; + + public MITraceRecord(MIOutput out) { + super(out); + parse(); + } + + public MIFrame getStackFrame() { + return fStackFrame; + } + + public Integer getTracepointId() { + return fTracepoint; + } + + public Integer getRecordIndex() { + return fRecordIndex; + } + + private void parse() { + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("traceframe")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIConst) { + try { + fRecordIndex = Integer.parseInt(((MIConst)val).getString()); + } catch (NumberFormatException e) {} + } + } else if (var.equals("tracepoint")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIConst) { + try { + fTracepoint = Integer.parseInt(((MIConst)val).getString()); + } catch (NumberFormatException e) {} + } + } else if (var.equals("frame")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + fStackFrame = new MIFrame((MITuple)value); + } + } + } + } + } + } +}