diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2.java index 73a55d3dc45..63ce356687d 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2.java @@ -7,6 +7,7 @@ * * Contributors: * Onur Akdemir (TUBITAK BILGEM-ITI) - Multi-process debugging (Bug 237306) + * Marc Khouzam (Ericsson) - Workaround for Bug 352998 *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; @@ -14,6 +15,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.eclipse.cdt.debug.core.CDebugUtils; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfExecutor; import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; @@ -56,6 +58,15 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 { private IGDBControl fCommandControl; private IGDBBackend fBackend; + private final static String INVALID = "invalid"; //$NON-NLS-1$ + + /** + * Keep track if we need to reconnect to the target + * due to a workaround because of a GDB 7.2 bug. + * Bug 352998 + */ + private boolean fNeedToReconnect; + /** * Set of processes that are currently being restarted. * We use this set for such things as not removing breakpoints @@ -162,7 +173,6 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 { if (isInitialProcess()) { // If it is the first inferior, GDB has already created it for us // We really should get the id from GDB instead of hard-coding it - setIsInitialProcess(false); fContainerDmc = createContainerContext(procCtx, "i1"); //$NON-NLS-1$ rm.done(); return; @@ -184,10 +194,45 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 { } }); } + }, + new Step() { + @Override + public void execute(final RequestMonitor rm) { + // Because of a GDB 7.2 bug, for remote-attach sessions, + // we need to be disconnected from the target + // when we set the very first binary to be used. + // So, lets disconnect. + // Bug 352998 + if (needFixForGDB72Bug352998()) { + // The bug only applies to remote sessions + if (fBackend.getSessionType() == SessionType.REMOTE) { + assert fBackend.getIsAttachSession(); + assert binaryPath != null; + + // We only need the workaround for the very first process we attach to + if (isInitialProcess()) { + ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, ICommandControlDMContext.class); + fCommandControl.queueCommand( + fCommandFactory.createMITargetDisconnect(controlDmc), + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm) { + @Override + protected void handleSuccess() { + fNeedToReconnect = true; + rm.done(); + } + }); + return; + } + } + } + + rm.done(); + } }, new Step() { @Override public void execute(RequestMonitor rm) { + // Now, set the binary to be used. if (binaryPath != null) { fCommandControl.queueCommand( fCommandFactory.createMIFileExecAndSymbols(fContainerDmc, binaryPath), @@ -198,6 +243,61 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 { rm.done(); } }, + new Step() { + @Override + @SuppressWarnings("unchecked") + public void execute(final RequestMonitor rm) { + // Because of a GDB 7.2 bug, for remote-attach sessions, + // we need to be disconnected from the target + // when we set the very first binary to be used. + // Now that we have disconnected and set the binary, + // lets reconnect. + // Bug 352998 + if (fNeedToReconnect) { + ILaunch launch = (ILaunch)procCtx.getAdapter(ILaunch.class); + assert launch != null; + if (launch != null) { + Map attributes = null; + try { + attributes = launch.getLaunchConfiguration().getAttributes(); + } catch (CoreException e) {} + + boolean isTcpConnection = CDebugUtils.getAttribute( + attributes, + IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, + false); + + if (isTcpConnection) { + String remoteTcpHost = CDebugUtils.getAttribute( + attributes, + IGDBLaunchConfigurationConstants.ATTR_HOST, INVALID); + String remoteTcpPort = CDebugUtils.getAttribute( + attributes, + IGDBLaunchConfigurationConstants.ATTR_PORT, INVALID); + + fCommandControl.queueCommand( + fCommandFactory.createMITargetSelect(fCommandControl.getContext(), + remoteTcpHost, remoteTcpPort, true), + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm)); + } else { + String serialDevice = CDebugUtils.getAttribute( + attributes, + IGDBLaunchConfigurationConstants.ATTR_DEV, INVALID); + + fCommandControl.queueCommand( + fCommandFactory.createMITargetSelect(fCommandControl.getContext(), + serialDevice, true), + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm)); + } + return; + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Cannot reconnect to target.", null)); //$NON-NLS-1$ + } + } + + rm.done(); + } + }, // Now, actually do the attach new Step() { @Override @@ -248,12 +348,14 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 { rm.done(); } }, - // Store the fully formed container context so it can be returned to the caller. + // Store the fully formed container context so it can be returned to the caller + // and mark that we are not dealing with the first process anymore. new Step() { @Override public void execute(RequestMonitor rm) { dataRm.setData(fContainerDmc); - + setIsInitialProcess(false); + rm.done(); } }, @@ -402,5 +504,22 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 { super.eventDispatched(e); } + + /** + * GDB 7.2 has a bug which causes a gdbserver crash if we set the binary after we + * have connected to the target. Because GDB 7.2.1 was not released when CDT 8.0 + * was released, we need to workaround the bug in Eclipse. + * + * This method can be overridden to easily disable the workaround, for versions + * of GDB that no longer have the bug. + * + * See http://sourceware.org/ml/gdb-patches/2011-03/msg00531.html + * and Bug 352998 + * + * @since 4.1 + */ + protected boolean needFixForGDB72Bug352998() { + return true; + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2_1.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2_1.java new file mode 100644 index 00000000000..a8fb8160e83 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2_1.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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: + * Marc Khouzam (Ericsson) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.service; + +import org.eclipse.cdt.dsf.service.DsfSession; + +/** + * Version for GDB 7.2.1, which does not need a workaround + * for a bug in GDB 7.2 (Bug 352998) + * + * @since 4.1 + */ +public class GDBProcesses_7_2_1 extends GDBProcesses_7_2 { + + public GDBProcesses_7_2_1(DsfSession session) { + super(session); + } + + @Override + protected boolean needFixForGDB72Bug352998() { + return false; + } +} + 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 0964d762527..cd62c78403f 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 @@ -53,6 +53,8 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { public static final String GDB_7_1_VERSION = "7.1"; //$NON-NLS-1$ /** @since 4.0 */ public static final String GDB_7_2_VERSION = "7.2"; //$NON-NLS-1$ + /** @since 4.1 */ + public static final String GDB_7_2_1_VERSION = "7.2.1"; //$NON-NLS-1$ private final String fVersion; @@ -150,6 +152,9 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { @Override protected IProcesses createProcessesService(DsfSession session) { + if (GDB_7_2_1_VERSION.compareTo(fVersion) <= 0) { + return new GDBProcesses_7_2_1(session); + } if (GDB_7_2_VERSION.compareTo(fVersion) <= 0) { return new GDBProcesses_7_2(session); } 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 b6ae1dd5e47..0f11dfe4c6b 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 @@ -119,6 +119,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIStackListLocals; import org.eclipse.cdt.dsf.mi.service.command.commands.MIStackSelectFrame; import org.eclipse.cdt.dsf.mi.service.command.commands.MITargetAttach; import org.eclipse.cdt.dsf.mi.service.command.commands.MITargetDetach; +import org.eclipse.cdt.dsf.mi.service.command.commands.MITargetDisconnect; import org.eclipse.cdt.dsf.mi.service.command.commands.MITargetDownload; import org.eclipse.cdt.dsf.mi.service.command.commands.MITargetSelect; import org.eclipse.cdt.dsf.mi.service.command.commands.MITargetSelectCore; @@ -761,6 +762,11 @@ public class CommandFactory { return new MITargetSelectTFile(ctx, traceFilePath); } + /** @since 4.1 */ + public ICommand createMITargetDisconnect(ICommandControlDMContext ctx) { + return new MITargetDisconnect(ctx); + } + public ICommand createMITargetDownload(ICommandControlDMContext ctx) { return new MITargetDownload(ctx); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MITargetDisconnect.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MITargetDisconnect.java new file mode 100644 index 00000000000..dab22380375 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MITargetDisconnect.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * 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: + * Marc Khouzam (Ericsson) - Initial API and implementation + *******************************************************************************/ +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; + +/** + * This command disconnects from the remote target. + * @since 4.1 + */ +public class MITargetDisconnect extends MICommand { + + public MITargetDisconnect(ICommandControlDMContext ctx) { + super(ctx, "-target-disconnect"); //$NON-NLS-1$ + } +}