diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/MITargetDisconnect.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/MITargetDisconnect.java new file mode 100644 index 00000000000..2a526060ffe --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/commands/MITargetDisconnect.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * 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.internal.commands; + +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; +import org.eclipse.cdt.dsf.mi.service.command.commands.MICommand; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; + +/** + * This command disconnects from the remote target. + * This command is created in an internal package for the maintenance branch only. + */ +public class MITargetDisconnect extends MICommand { + + public MITargetDisconnect(ICommandControlDMContext ctx) { + super(ctx, "-target-disconnect"); //$NON-NLS-1$ + } +} 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..7874b8f6e0c 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; @@ -27,6 +29,7 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.internal.commands.MITargetDisconnect; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; @@ -56,6 +59,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 +174,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 +195,46 @@ 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( + // We don't use the command factory because we couldn't add the API to the maintenance branch + new MITargetDisconnect(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 +245,62 @@ 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) { + fNeedToReconnect = false; + 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 +351,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 +507,17 @@ 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. + * + * See http://sourceware.org/ml/gdb-patches/2011-03/msg00531.html + * and Bug 352998 + * */ + private boolean needFixForGDB72Bug352998() { + return true; + } }