1
0
Fork 0
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:
Marc Khouzam 2011-04-20 18:10:37 +00:00
parent 096a053e12
commit cfd1f8213c
8 changed files with 199 additions and 11 deletions

View file

@ -52,6 +52,7 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
protected Button fNonStopCheckBox; protected Button fNonStopCheckBox;
protected Button fReverseCheckBox; protected Button fReverseCheckBox;
protected Button fUpdateThreadlistOnSuspend; protected Button fUpdateThreadlistOnSuspend;
protected Button fDebugOnFork;
private IMILaunchConfigurationComponent fSolibBlock; private IMILaunchConfigurationComponent fSolibBlock;
private boolean fIsInitializing = false; private boolean fIsInitializing = false;
@ -79,6 +80,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND, configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT); IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT);
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_DEBUG_ON_FORK,
IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_ON_FORK_DEFAULT);
if (fSolibBlock != null) if (fSolibBlock != null)
fSolibBlock.setDefaults(configuration); fSolibBlock.setDefaults(configuration);
@ -130,6 +133,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
boolean updateThreadsOnSuspend = getBooleanAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND, boolean updateThreadsOnSuspend = getBooleanAttr(configuration, IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND,
IGDBLaunchConfigurationConstants.DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND_DEFAULT); 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) if (fSolibBlock != null)
fSolibBlock.initializeFrom(configuration); fSolibBlock.initializeFrom(configuration);
@ -138,6 +143,7 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
fNonStopCheckBox.setSelection(nonStopMode); fNonStopCheckBox.setSelection(nonStopMode);
fReverseCheckBox.setSelection(reverseEnabled); fReverseCheckBox.setSelection(reverseEnabled);
fUpdateThreadlistOnSuspend.setSelection(updateThreadsOnSuspend); fUpdateThreadlistOnSuspend.setSelection(updateThreadsOnSuspend);
fDebugOnFork.setSelection(debugOnFork);
setInitializing(false); setInitializing(false);
} }
@ -152,8 +158,9 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer {
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
fReverseCheckBox.getSelection()); fReverseCheckBox.getSelection());
configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_UPDATE_THREADLIST_ON_SUSPEND, 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) if (fSolibBlock != null)
fSolibBlock.performApply(configuration); 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$ fUpdateThreadlistOnSuspend = addCheckbox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.update_thread_list_on_suspend")); //$NON-NLS-1$
// This checkbox needs an explanation. Attach context help to it. // 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$ 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) { public void createSolibTab(TabFolder tabFolder) {

View file

@ -24,6 +24,7 @@ GDBDebuggerPage.shared_libraries=Shared Libraries
GDBDebuggerPage.nonstop_mode=Non-stop mode (Note: Requires non-stop GDB) GDBDebuggerPage.nonstop_mode=Non-stop mode (Note: Requires non-stop GDB)
GDBDebuggerPage.reverse_Debugging=Enable Reverse Debugging at startup (Note: Requires Reverse 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.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.0=Debugger executable must be specified.
StandardGDBDebuggerPage.1=GDB Debugger Options StandardGDBDebuggerPage.1=GDB Debugger Options
StandardGDBDebuggerPage.2=Main StandardGDBDebuggerPage.2=Main

View file

@ -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$ 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. * Launch configuration attribute value. The key is ATTR_DEBUG_NAME.
@ -159,5 +168,12 @@ public class IGDBLaunchConfigurationConstants {
* @since 3.0 * @since 3.0
*/ */
public static final String DEBUGGER_POST_MORTEM_TYPE_DEFAULT = DEBUGGER_POST_MORTEM_CORE_FILE; 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;
} }

View file

@ -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));
}
}

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -10,6 +10,11 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service.command; 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.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.debug.core.ILaunchConfiguration; 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); super(session, config, factory);
setUseThreadGroupOptions(true); setUseThreadGroupOptions(true);
} }
@Override
protected Sequence getCompleteInitializationSequence(Map<String, Object> attributes, RequestMonitorWithProgress rm) {
return new FinalLaunchSequence_7_2(getSession(), attributes, rm);
}
} }

View file

@ -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.MIGDBSetArgs;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetAutoSolib; 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.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.MIGDBSetEnv;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetNonStop; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetNonStop;
import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetPagination; import org.eclipse.cdt.dsf.mi.service.command.commands.MIGDBSetPagination;
@ -596,6 +597,11 @@ public class CommandFactory {
return new MIGDBSetBreakpointPending(ctx, enable); 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) { public ICommand<MIInfo> createMIGDBSetEnv(ICommandControlDMContext dmc, String name) {
return new MIGDBSetEnv(dmc, name); return new MIGDBSetEnv(dmc, name);
} }

View file

@ -211,8 +211,7 @@ public class MIRunControlEventProcessor_7_0
fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
} }
} else if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent) || //$NON-NLS-1$ //$NON-NLS-2$ } 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$
String groupId = null; String groupId = null;
String pId = null; String pId = null;
@ -242,13 +241,29 @@ public class MIRunControlEventProcessor_7_0
if (pId != null && procService != null) { if (pId != null && procService != null) {
IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, pId); IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, pId);
MIEvent<?> event = null; MIEvent<?> event = new MIThreadGroupCreatedEvent(procDmc, exec.getToken(), groupId);
if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
event = new MIThreadGroupCreatedEvent(procDmc, exec.getToken(), groupId); }
} else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ } else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$
event = new MIThreadGroupExitedEvent(procDmc, exec.getToken(), groupId); 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()); fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
} }
} }

View file

@ -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$
}
}