mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 09:46:02 +02:00
Bug 340697: Auto attach to processes forked by the process being debugged
This commit is contained in:
parent
096a053e12
commit
cfd1f8213c
8 changed files with 199 additions and 11 deletions
|
@ -52,6 +52,7 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
|
|||
protected Button fNonStopCheckBox;
|
||||
protected Button fReverseCheckBox;
|
||||
protected Button fUpdateThreadlistOnSuspend;
|
||||
protected Button fDebugOnFork;
|
||||
|
||||
private IMILaunchConfigurationComponent fSolibBlock;
|
||||
private boolean fIsInitializing = false;
|
||||
|
@ -79,6 +80,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
|
|||
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
|
||||
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
|
||||
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT);
|
||||
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_DEBUG_ON_FORK,
|
||||
IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_ON_FORK_DEFAULT);
|
||||
|
||||
if (fSolibBlock != null)
|
||||
fSolibBlock.setDefaults(configuration);
|
||||
|
@ -130,6 +133,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
|
|||
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
|
||||
boolean updateThreadsOnSuspend = getBooleanAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
|
||||
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT);
|
||||
boolean debugOnFork = getBooleanAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_DEBUG_ON_FORK,
|
||||
IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_ON_FORK_DEFAULT);
|
||||
|
||||
if (fSolibBlock != null)
|
||||
fSolibBlock.initializeFrom(configuration);
|
||||
|
@ -138,6 +143,7 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
|
|||
fNonStopCheckBox.setSelection(nonStopMode);
|
||||
fReverseCheckBox.setSelection(reverseEnabled);
|
||||
fUpdateThreadlistOnSuspend.setSelection(updateThreadsOnSuspend);
|
||||
fDebugOnFork.setSelection(debugOnFork);
|
||||
|
||||
setInitializing(false);
|
||||
}
|
||||
|
@ -152,8 +158,9 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
|
|||
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
|
||||
fReverseCheckBox.getSelection());
|
||||
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
|
||||
fUpdateThreadlistOnSuspend.getSelection());
|
||||
|
||||
fUpdateThreadlistOnSuspend.getSelection());
|
||||
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_DEBUG_ON_FORK,
|
||||
fDebugOnFork.getSelection());
|
||||
if (fSolibBlock != null)
|
||||
fSolibBlock.performApply(configuration);
|
||||
}
|
||||
|
@ -303,6 +310,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
|
|||
fUpdateThreadlistOnSuspend = addCheckbox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.update_thread_list_on_suspend")); //$NON-NLS-1$
|
||||
// This checkbox needs an explanation. Attach context help to it.
|
||||
PlatformUI.getWorkbench().getHelpSystem().setHelp(fUpdateThreadlistOnSuspend, GdbUIPlugin.PLUGIN_ID + ".update_threadlist_button_context"); //$NON-NLS-1$
|
||||
|
||||
fDebugOnFork = addCheckbox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.Automatically_debug_forked_processes")); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public void createSolibTab(TabFolder tabFolder) {
|
||||
|
|
|
@ -24,6 +24,7 @@ GDBDebuggerPage.shared_libraries=Shared Libraries
|
|||
GDBDebuggerPage.nonstop_mode=Non-stop mode (Note: Requires non-stop GDB)
|
||||
GDBDebuggerPage.reverse_Debugging=Enable Reverse Debugging at startup (Note: Requires Reverse GDB)
|
||||
GDBDebuggerPage.update_thread_list_on_suspend=Force thread list update on suspend
|
||||
GDBDebuggerPage.Automatically_debug_forked_processes=Automatically debug forked processes (Note: Requires Multi Process GDB)
|
||||
StandardGDBDebuggerPage.0=Debugger executable must be specified.
|
||||
StandardGDBDebuggerPage.1=GDB Debugger Options
|
||||
StandardGDBDebuggerPage.2=Main
|
||||
|
|
|
@ -96,6 +96,15 @@ public class IGDBLaunchConfigurationConstants {
|
|||
*/
|
||||
public static final String ATTR_DEBUGGER_POST_MORTEM_TYPE = GdbPlugin.PLUGIN_ID + ".POST_MORTEM_TYPE"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Launch configuration attribute key. Boolean value to set the 'detach-on-fork' GDB option.
|
||||
* When detach-on-fork is off, we will automatically attach to forked processes. This will yield
|
||||
* a multi-process session, which is supported with GDB >= 7.2
|
||||
* Note that detach-on-fork == !ATTR_DEBUGGER_DEBUG_ON_FORK
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String ATTR_DEBUGGER_DEBUG_ON_FORK = GdbPlugin.PLUGIN_ID + ".DEBUG_ON_FORK"; //$NON-NLS-1$
|
||||
|
||||
|
||||
/**
|
||||
* Launch configuration attribute value. The key is ATTR_DEBUG_NAME.
|
||||
|
@ -160,4 +169,11 @@ public class IGDBLaunchConfigurationConstants {
|
|||
*/
|
||||
public static final String DEBUGGER_POST_MORTEM_TYPE_DEFAULT = DEBUGGER_POST_MORTEM_CORE_FILE;
|
||||
|
||||
/**
|
||||
* Launch configuration attribute value. The key is ATTR_DEBUGGER_DEBUG_ON_FORK.
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final boolean DEBUGGER_DEBUG_ON_FORK_DEFAULT = false;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 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.launching;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.debug.core.CDebugUtils;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
|
||||
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitorWithProgress;
|
||||
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
|
||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
||||
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
|
||||
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
|
||||
/**
|
||||
* Subclass for GDB >= 7.2.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class FinalLaunchSequence_7_2 extends FinalLaunchSequence {
|
||||
|
||||
private IGDBControl fGdbControl;
|
||||
private DsfSession fSession;
|
||||
|
||||
// The launchConfiguration attributes
|
||||
private Map<String, Object> fAttributes;
|
||||
|
||||
public FinalLaunchSequence_7_2(DsfSession session, Map<String, Object> attributes, RequestMonitorWithProgress rm) {
|
||||
super(session, attributes, rm);
|
||||
fSession = session;
|
||||
fAttributes = attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getExecutionOrder(String group) {
|
||||
if (GROUP_TOP_LEVEL.equals(group)) {
|
||||
// Initialize the list with the base class' steps
|
||||
// We need to create a list that we can modify, which is why we create our own ArrayList.
|
||||
List<String> orderList = new ArrayList<String>(Arrays.asList(super.getExecutionOrder(GROUP_TOP_LEVEL)));
|
||||
|
||||
// Now insert our steps right after the initialization of the base class.
|
||||
orderList.add(orderList.indexOf("stepInitializeFinalLaunchSequence") + 1, "stepInitializeFinalLaunchSequence_7_2"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
orderList.add(orderList.indexOf("stepSetBreakpointPending") + 1, "stepDetachOnFork"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
return orderList.toArray(new String[orderList.size()]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the members of the FinalLaunchSequence_7_2 class.
|
||||
* This step is mandatory for the rest of the sequence to complete.
|
||||
*/
|
||||
@Execute
|
||||
public void stepInitializeFinalLaunchSequence_7_2(RequestMonitor rm) {
|
||||
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSession.getId());
|
||||
fGdbControl = tracker.getService(IGDBControl.class);
|
||||
tracker.dispose();
|
||||
|
||||
if (fGdbControl == null) {
|
||||
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Cannot obtain service", null)); //$NON-NLS-1$
|
||||
rm.done();
|
||||
return;
|
||||
}
|
||||
|
||||
rm.done();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell GDB whether to automatically attach to a forked process or not.
|
||||
*/
|
||||
@Execute
|
||||
public void stepDetachOnFork(final RequestMonitor rm) {
|
||||
boolean debugOnFork = CDebugUtils.getAttribute(fAttributes,
|
||||
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_DEBUG_ON_FORK,
|
||||
IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_ON_FORK_DEFAULT);
|
||||
|
||||
fGdbControl.queueCommand(
|
||||
fGdbControl.getCommandFactory().createMIGDBSetDetachOnFork(fGdbControl.getContext(), !debugOnFork),
|
||||
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2010 Ericsson and others.
|
||||
* Copyright (c) 2010, 2011 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
|
||||
|
@ -10,6 +10,11 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.service.command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.RequestMonitorWithProgress;
|
||||
import org.eclipse.cdt.dsf.concurrent.Sequence;
|
||||
import org.eclipse.cdt.dsf.gdb.launching.FinalLaunchSequence_7_2;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.debug.core.ILaunchConfiguration;
|
||||
|
@ -23,4 +28,10 @@ public class GDBControl_7_2 extends GDBControl_7_0 implements IGDBControl {
|
|||
super(session, config, factory);
|
||||
setUseThreadGroupOptions(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sequence getCompleteInitializationSequence(Map<String, Object> attributes, RequestMonitorWithProgress rm) {
|
||||
return new FinalLaunchSequence_7_2(getSession(), attributes, rm);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSet;
|
|||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetArgs;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetAutoSolib;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetBreakpointPending;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetDetachOnFork;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetEnv;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetNonStop;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetPagination;
|
||||
|
@ -596,6 +597,11 @@ public class CommandFactory {
|
|||
return new MIGDBSetBreakpointPending(ctx, enable);
|
||||
}
|
||||
|
||||
/** @since 4.0 */
|
||||
public ICommand<MIInfo> createMIGDBSetDetachOnFork(ICommandControlDMContext ctx, boolean detach) {
|
||||
return new MIGDBSetDetachOnFork(ctx, detach);
|
||||
}
|
||||
|
||||
public ICommand<MIInfo> createMIGDBSetEnv(ICommandControlDMContext dmc, String name) {
|
||||
return new MIGDBSetEnv(dmc, name);
|
||||
}
|
||||
|
|
|
@ -211,8 +211,7 @@ public class MIRunControlEventProcessor_7_0
|
|||
|
||||
fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
|
||||
}
|
||||
} else if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent) || //$NON-NLS-1$ //$NON-NLS-2$
|
||||
"thread-group-exited".equals(miEvent)) { //$NON-NLS-1$
|
||||
} else if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
String groupId = null;
|
||||
String pId = null;
|
||||
|
@ -242,13 +241,29 @@ public class MIRunControlEventProcessor_7_0
|
|||
if (pId != null && procService != null) {
|
||||
IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, pId);
|
||||
|
||||
MIEvent<?> event = null;
|
||||
if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
event = new MIThreadGroupCreatedEvent(procDmc, exec.getToken(), groupId);
|
||||
} else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$
|
||||
event = new MIThreadGroupExitedEvent(procDmc, exec.getToken(), groupId);
|
||||
}
|
||||
MIEvent<?> event = new MIThreadGroupCreatedEvent(procDmc, exec.getToken(), groupId);
|
||||
fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
|
||||
}
|
||||
} else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$
|
||||
String groupId = null;
|
||||
|
||||
MIResult[] results = exec.getMIResults();
|
||||
for (int i = 0; i < results.length; i++) {
|
||||
String var = results[i].getVariable();
|
||||
MIValue val = results[i].getMIValue();
|
||||
if (var.equals("id")) { //$NON-NLS-1$
|
||||
if (val instanceof MIConst) {
|
||||
groupId = ((MIConst) val).getString().trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class);
|
||||
if (procService != null) {
|
||||
IContainerDMContext containerDmc = procService.createContainerContextFromGroupId(fControlDmc, groupId);
|
||||
IProcessDMContext procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class);
|
||||
|
||||
MIEvent<?> event = new MIThreadGroupExitedEvent(procDmc, exec.getToken(), groupId);
|
||||
fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 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.debug.service.command.ICommandControlService.ICommandControlDMContext;
|
||||
|
||||
/**
|
||||
*
|
||||
* -gdb-set detach-on-fork [on|off]
|
||||
*
|
||||
* When 'on', tells GDB to detach from process that has been forked.
|
||||
* When 'off', automatically starts debugging a forked process in a multi-process session.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class MIGDBSetDetachOnFork extends MIGDBSet
|
||||
{
|
||||
public MIGDBSetDetachOnFork(ICommandControlDMContext ctx, boolean detach) {
|
||||
super(ctx, new String[] {"detach-on-fork", detach ? "on" : "off"});//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue