From e8480ca0f8c72f1eb1a7d31f6c48789eef1bf9ba Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Wed, 9 Nov 2016 22:51:21 -0500 Subject: [PATCH] Bug 498782 - add synchronize of process selection between the DV and GDB This patch synchronizes the GDB focus when the user selects a process node in the DV. When the user selects a new process (inferior) from the GDB console, we are already synchronizing the DV to the thread/frame that GDB selects from that process. Change-Id: I11dfd175d51ec49e969f4d07288f80f7ea72a3e1 --- .../ui/sync/GdbDebugContextSyncManager.java | 7 ++- .../service/GDBFocusSynchronizer.java | 61 ++++++++++++++++++- .../mi/service/command/CommandFactory.java | 10 ++- .../service/command/commands/CLIInferior.java | 26 ++++++++ 4 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInferior.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/sync/GdbDebugContextSyncManager.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/sync/GdbDebugContextSyncManager.java index ffa0e6ddc6d..96cce9903e9 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/sync/GdbDebugContextSyncManager.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/sync/GdbDebugContextSyncManager.java @@ -12,6 +12,7 @@ import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.gdb.internal.service.IGDBFocusSynchronizer; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; @@ -46,8 +47,10 @@ public class GdbDebugContextSyncManager implements IDebugContextListener { if (context != null) { final IDMContext dmc = context.getAdapter(IDMContext.class); - if (dmc instanceof IMIExecutionDMContext || dmc instanceof IFrameDMContext) { - // A thread or stack frame was selected. In either case, have GDB switch to the new + if (dmc instanceof IMIContainerDMContext || + dmc instanceof IMIExecutionDMContext || + dmc instanceof IFrameDMContext) { + // A process, thread or stack frame was selected. In each case, have GDB switch to the new // corresponding thread, if required. // Resolve the debug session diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/GDBFocusSynchronizer.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/GDBFocusSynchronizer.java index 179496044a8..06ea5209fa3 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/GDBFocusSynchronizer.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/GDBFocusSynchronizer.java @@ -29,6 +29,7 @@ import org.eclipse.cdt.dsf.debug.service.command.IEventListener; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; +import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.output.MIConst; @@ -70,7 +71,7 @@ import org.osgi.framework.BundleContext; public class GDBFocusSynchronizer extends AbstractDsfService implements IGDBFocusSynchronizer, IEventListener { /** This service's opinion of what is the current GDB focus - it can be - * a thread or stack frame context */ + * a process, thread or stack frame context */ private IDMContext fCurrentGDBFocus; private IStack fStackService; @@ -170,6 +171,10 @@ public class GDBFocusSynchronizer extends AbstractDsfService implements IGDBFocu } }); } + // new selection is a process? + else if (elem instanceof IMIContainerDMContext) { + setProcessFocus((IMIContainerDMContext)elem, rm); + } else { assert false; rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, @@ -177,7 +182,59 @@ public class GDBFocusSynchronizer extends AbstractDsfService implements IGDBFocu return; } } - + + protected void setProcessFocus(IMIContainerDMContext newProc, RequestMonitor rm) { + if (newProc == null) { + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + INVALID_HANDLE, "GdbFocusSynchronizer unable to resolve process context for the selected element", null)); //$NON-NLS-1$ + return; + } + // There is no MI command to set the inferior. We could use the CLI 'inferior' command, but it would then + // generate a =thread-selected event, which would cause us to change the selection in the Debug view and + // select the stack frame of the first thread, or the first thread itself if it is running. + // That would prevent the user from being able to leave the selection to a process node. + // What we can do instead, is tell GDB to select the first thread of that inferior, which is what + // GDB would do anyway, but since we have an MI -thread-select command it will prevent GDB from + // issuing a =thread-selected event. + fProcesses.getProcessesBeingDebugged(newProc, new ImmediateDataRequestMonitor(rm) { + @Override + protected void handleSuccess() { + if (getData().length > 0) { + IDMContext finalThread = getData()[0]; + if (finalThread instanceof IMIExecutionDMContext) { + setThreadFocus((IMIExecutionDMContext)(finalThread), new ImmediateRequestMonitor(rm) { + @Override + protected void handleSuccess() { + // update the current focus, to match new GDB focus + fCurrentGDBFocus = finalThread; + rm.done(); + } + }); + return; + } + rm.done(); + } else { + // If there are no threads, it probably implies the inferior is not running + // e.g., an exited process. In this case, we cannot set the thread, but it + // then becomes safe to set the inferior using the CLI command since + // there is no thread for that inferior and therefore no =thread-selected event + String miInferiorId = newProc.getGroupId(); + // Remove the 'i' prefix + String cliInferiorId = miInferiorId.substring(1, miInferiorId.length()); + ICommand command = fCommandFactory.createCLIInferior(fGdbcontrol.getContext(), cliInferiorId); + fGdbcontrol.queueCommand(command, new ImmediateDataRequestMonitor (rm) { + @Override + protected void handleSuccess() { + // update the current focus, to match new GDB focus + fCurrentGDBFocus = newProc; + rm.done(); + } + }); + } + } + }); + } + protected void setThreadFocus(IMIExecutionDMContext newThread, RequestMonitor rm) { if (newThread == null) { rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, 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 16eb5565225..5e89614a0f9 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 @@ -31,6 +31,7 @@ package org.eclipse.cdt.dsf.mi.service.command; +import org.eclipse.cdt.debug.core.model.IChangeReverseMethodHandler.ReverseDebugMethod; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; import org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext; @@ -53,6 +54,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.CLIAttach; import org.eclipse.cdt.dsf.mi.service.command.commands.CLICatch; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIDetach; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIExecAbort; +import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInferior; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoBreak; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoProgram; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoRecord; @@ -195,6 +197,7 @@ import org.eclipse.cdt.dsf.mi.service.command.output.CLIAddressableSizeInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLICatchInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoBreakInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoProgramInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoRecordInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoSharedLibraryInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoThreadsInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIShowEndianInfo; @@ -242,8 +245,6 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIVarSetFormatInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIVarShowAttributesInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIVarShowFormatInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIVarUpdateInfo; -import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoRecordInfo; -import org.eclipse.cdt.debug.core.model.IChangeReverseMethodHandler.ReverseDebugMethod; /** * Factory to create MI/CLI commands. @@ -279,6 +280,11 @@ public class CommandFactory { return new CLIExecAbort(ctx); } + /** @since 5.2 */ + public ICommand createCLIInferior(ICommandControlDMContext ctx, String inferiorId) { + return new CLIInferior(ctx, inferiorId); + } + /** @since 4.2 */ public ICommand createCLIInfoBreak(IDMContext ctx) { return new CLIInfoBreak(ctx); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInferior.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInferior.java new file mode 100644 index 00000000000..f7e60bcbe37 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInferior.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2016 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 + *******************************************************************************/ + +package org.eclipse.cdt.dsf.mi.service.command.commands; + +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; + +/** + * Selects the specified inferior in GDB. + * + * @since 5.2 + */ +public class CLIInferior extends MIInterpreterExecConsole { + + private static final String INFERIOR = "inferior "; //$NON-NLS-1$ + + public CLIInferior(ICommandControlDMContext ctx, String inferiorId) { + super(ctx, INFERIOR + inferiorId); + } +}