1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 402054 - Debugger does not display exit code of an application. Fix

for local session and GDB >= 7.3

Change-Id: I06cd9f1087b9b5c241410040028d1e5e1ef7476e
Reviewed-on: https://git.eclipse.org/r/12439
Reviewed-by: Marc Khouzam <marc.khouzam@ericsson.com>
IP-Clean: Marc Khouzam <marc.khouzam@ericsson.com>
Tested-by: Marc Khouzam <marc.khouzam@ericsson.com>
This commit is contained in:
Marc Khouzam 2013-04-27 16:57:24 -04:00
parent de790b478e
commit c0ff399bea
7 changed files with 187 additions and 11 deletions

View file

@ -59,5 +59,12 @@ public interface IGdbDebugConstants {
*/ */
public static final String GDB_PROCESS_CREATION_VALUE = PREFIX + "gdbProcess"; //$NON-NLS-1$ public static final String GDB_PROCESS_CREATION_VALUE = PREFIX + "gdbProcess"; //$NON-NLS-1$
/**
* Attribute key that when set, indicates that the inferior process has properly exited,
* and its exit value can be used.
* @since 4.2
*/
public static final String INFERIOR_EXITED_ATTR = PREFIX + "inferiorExited"; //$NON-NLS-1$
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2011 Ericsson and others. * Copyright (c) 2011, 2013 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
@ -7,14 +7,22 @@
* *
* Contributors: * Contributors:
* Ericsson - Initial API and implementation * Ericsson - Initial API and implementation
* Marc Khouzam (Ericsson) - Display exit code in process console (Bug 402054)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.dsf.gdb.launching; package org.eclipse.cdt.dsf.gdb.launching;
import java.util.Map; import java.util.Map;
import org.eclipse.cdt.dsf.gdb.IGdbDebugConstants;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.RuntimeProcess; import org.eclipse.debug.core.model.RuntimeProcess;
import com.ibm.icu.text.MessageFormat;
/** /**
* A process for the inferior to know it belongs to a DSF-GDB session * A process for the inferior to know it belongs to a DSF-GDB session
* *
@ -27,4 +35,45 @@ public class InferiorRuntimeProcess extends RuntimeProcess {
super(launch, process, name, attributes); super(launch, process, name, attributes);
} }
@Override
protected void terminated() {
super.terminated();
setConsoleTerminatedLabel();
}
// Inspired from org.eclipse.debug.internal.ui.views.console.ProcessConsole#computeName
// We set the IProcess.ATTR_PROCESS_LABEL to modify the console title but not the process label
// of the debug view. Overriding getLabel() affects the element in the debug view also, so
// we don't do that.
private void setConsoleTerminatedLabel() {
String label = getLabel();
String type = null;
ILaunchConfiguration config = getLaunch().getLaunchConfiguration();
try {
type = config.getType().getName();
} catch (CoreException e) {
}
StringBuffer buffer = new StringBuffer();
buffer.append(config.getName());
if (type != null) {
buffer.append(" ["); //$NON-NLS-1$
buffer.append(type);
buffer.append("] "); //$NON-NLS-1$
}
buffer.append(label);
if (getAttribute(IGdbDebugConstants.INFERIOR_EXITED_ATTR) != null) {
// Add the exit code to the label if the inferior properly exited.
try {
buffer.insert(0, MessageFormat.format(LaunchMessages.getString("InferiorRuntimeProcess_ExitValue"), //$NON-NLS-1$
new Object[] { getExitValue() }));
} catch (DebugException e) {
// Process not terminated. Should not happen. But even so, we should use the plain label.
}
}
label = buffer.toString();
setAttribute(IProcess.ATTR_PROCESS_LABEL, label);
}
} }

View file

@ -176,3 +176,5 @@ LocalCDILaunchDelegate.9=Eclipse runtime does not support working directory.
LocalCDILaunchDelegate.10=Failed to set program arguments, environment or working directory. LocalCDILaunchDelegate.10=Failed to set program arguments, environment or working directory.
ServicesLaunchSequence_0=Initializing debugger services ServicesLaunchSequence_0=Initializing debugger services
ServicesLaunchSequence_1=Aborting debugger services initialization ServicesLaunchSequence_1=Aborting debugger services initialization
InferiorRuntimeProcess_ExitValue=(exit value: {0})

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2009, 2011 QNX Software Systems and others. * Copyright (c) 2009, 2013 QNX Software Systems 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
@ -9,6 +9,7 @@
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
* Hewlett-Packard Development Company - fix for bug 109733 * Hewlett-Packard Development Company - fix for bug 109733
* Wind River Systems - Modified for new DSF Reference Implementation * Wind River Systems - Modified for new DSF Reference Implementation
* Marc Khouzam (Ericsson) - Display exit code in process console (Bug 402054)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command; package org.eclipse.cdt.dsf.mi.service.command;
@ -41,10 +42,14 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandListener;
import org.eclipse.cdt.dsf.debug.service.command.ICommandResult; import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
import org.eclipse.cdt.dsf.debug.service.command.ICommandToken; import org.eclipse.cdt.dsf.debug.service.command.ICommandToken;
import org.eclipse.cdt.dsf.debug.service.command.IEventListener; import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
import org.eclipse.cdt.dsf.gdb.IGdbDebugConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.launching.InferiorRuntimeProcess;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
import org.eclipse.cdt.dsf.mi.service.MIProcesses;
import org.eclipse.cdt.dsf.mi.service.command.commands.CLICommand; import org.eclipse.cdt.dsf.mi.service.command.commands.CLICommand;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadGroupExitedEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIGDBShowExitCodeInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIGDBShowExitCodeInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord; import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
@ -56,6 +61,8 @@ import org.eclipse.cdt.utils.pty.PTY;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
/** /**
* This Process implementation tracks the process that is being debugged * This Process implementation tracks the process that is being debugged
@ -253,6 +260,11 @@ public class MIInferiorProcess extends Process
} }
} }
// The below should only be used for GDB < 7.3 because $_exitcode does not
// support multi-process properly. Note that for GDB 7.2, there is no proper
// solution because although we support multi-process, $_exitcode was still the
// only way to get the exit code. For GDB >= 7.3, we can use =thread-group-exited
// which provides the exit code; in fact, fExitCode will already be set for that case.
try { try {
Query<Integer> exitCodeQuery = new Query<Integer>() { Query<Integer> exitCodeQuery = new Query<Integer>() {
@Override @Override
@ -446,6 +458,33 @@ public class MIInferiorProcess extends Process
} }
} }
/** @since 4.2 */
@DsfServiceEventHandler
public void eventDispatched(MIThreadGroupExitedEvent e) {
if (fContainerDMContext instanceof IMIContainerDMContext) {
if (((IMIContainerDMContext)fContainerDMContext).getGroupId().equals(e.getGroupId())) {
if (fStarted) {
// Only handle this event if this process was already
// started. This is to protect ourselves in the case of
// a restart, where the new inferior is already created
// and gets the exited event for the old inferior.
String exitCode = e.getExitCode();
if (exitCode != null) {
setExitCodeAttribute();
try {
// Must use 'decode' since GDB returns an octal value
Integer decodedExitCode = Integer.decode(exitCode);
synchronized(this) {
fExitCode = decodedExitCode;
}
} catch (NumberFormatException exception) {
}
}
}
}
}
}
/** /**
* @since 4.0 * @since 4.0
*/ */
@ -486,4 +525,34 @@ public class MIInferiorProcess extends Process
public void eventDispatched(ICommandControlShutdownDMEvent e) { public void eventDispatched(ICommandControlShutdownDMEvent e) {
dispose(); dispose();
} }
/**
* Set an attribute in the inferior process of the launch to indicate
* that the inferior has properly exited and its exit value can be used.
*/
@ConfinedToDsfExecutor("fSession#getExecutor")
private void setExitCodeAttribute() {
// Update the console label to contain the exit code
ILaunch launch = (ILaunch)fSession.getModelAdapter(ILaunch.class);
IProcess[] launchProcesses = launch.getProcesses();
for (IProcess proc : launchProcesses) {
if (proc instanceof InferiorRuntimeProcess) {
InferiorRuntimeProcess process = (InferiorRuntimeProcess)proc;
String groupAttribute = process.getAttribute(IGdbDebugConstants.INFERIOR_GROUPID_ATTR);
// if the groupAttribute is not set in the process we know we are dealing
// with single process debugging so the one process is the one we want.
// If the groupAttribute is set, then we must make sure it is the proper inferior
if (fContainerDMContext instanceof IMIContainerDMContext) {
if (groupAttribute == null || groupAttribute.equals(MIProcesses.UNIQUE_GROUP_ID) ||
groupAttribute.equals(((IMIContainerDMContext)fContainerDMContext).getGroupId())) {
// Simply set the attribute that indicates the inferior has properly exited and its
// exit code can be used.
process.setAttribute(IGdbDebugConstants.INFERIOR_EXITED_ATTR, ""); //$NON-NLS-1$
return;
}
}
}
}
}
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2006, 2010 Wind River Systems and others. * Copyright (c) 2006, 2013 Wind River Systems 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
@ -9,6 +9,7 @@
* Wind River Systems - initial API and implementation * Wind River Systems - initial API and implementation
* Ericsson - Version 7.0 * Ericsson - Version 7.0
* Mikhail Khodjaiants (Mentor Graphics) - Refactor common code in GDBControl* classes (bug 372795) * Mikhail Khodjaiants (Mentor Graphics) - Refactor common code in GDBControl* classes (bug 372795)
* Marc Khouzam (Ericsson) - Display exit code in process console (Bug 402054)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command; package org.eclipse.cdt.dsf.mi.service.command;
@ -264,7 +265,7 @@ public class MIRunControlEventProcessor_7_0
IContainerDMContext containerDmc = procService.createContainerContextFromGroupId(fControlDmc, groupId); IContainerDMContext containerDmc = procService.createContainerContextFromGroupId(fControlDmc, groupId);
IProcessDMContext procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class); IProcessDMContext procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class);
MIEvent<?> event = new MIThreadGroupExitedEvent(procDmc, exec.getToken(), groupId); MIEvent<?> event = new MIThreadGroupExitedEvent(procDmc, exec.getToken(), exec.getMIResults());
fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
} }
} }

View file

@ -23,6 +23,9 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
* *
* Show the current value of a $_exitcode * Show the current value of a $_exitcode
* *
* With GDB 7.3, the exit code is provided by the MI =thread-group-exited event,
* which allows to handle multi-process situations.
*
*/ */
public class MIGDBShowExitCode extends MIDataEvaluateExpression<MIGDBShowExitCodeInfo> { public class MIGDBShowExitCode extends MIDataEvaluateExpression<MIGDBShowExitCodeInfo> {

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2008, 2009 Ericsson and others. * Copyright (c) 2008, 2013 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
@ -7,28 +7,73 @@
* *
* Contributors: * Contributors:
* Ericsson - Initial API and implementation * Ericsson - Initial API and implementation
* Marc Khouzam (Ericsson) - Display exit code in process console (Bug 402054)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.dsf.mi.service.command.events; package org.eclipse.cdt.dsf.mi.service.command.events;
import org.eclipse.cdt.dsf.concurrent.Immutable; import org.eclipse.cdt.dsf.concurrent.Immutable;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.cdt.dsf.mi.service.command.output.MIConst;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
/** /**
* This can only be detected by gdb/mi after GDB 6.8. * This can only be detected by gdb/mi starting with GDB 7.0.
* @since 1.1 * @since 1.1
*
*/ */
@Immutable @Immutable
public class MIThreadGroupExitedEvent extends MIEvent<IProcessDMContext> { public class MIThreadGroupExitedEvent extends MIEvent<IProcessDMContext> {
final private String fGroupId; private String fGroupId;
private String fExitCode;
/**
* @deprecated
*/
@Deprecated
public MIThreadGroupExitedEvent(IProcessDMContext ctx, int token, String groupId) { public MIThreadGroupExitedEvent(IProcessDMContext ctx, int token, String groupId) {
super(ctx, token, null); super(ctx, token, null);
fGroupId = groupId; fGroupId = groupId;
fExitCode = null;
}
/** @since 4.2 */
public MIThreadGroupExitedEvent(IProcessDMContext ctx, int token, MIResult[] results) {
super(ctx, token, results);
parse();
} }
public String getGroupId() { return fGroupId; } public String getGroupId() { return fGroupId; }
/**
* Returns the exit code of the process or null if there is no exit code.
* Note that this information is only available with GDB 7.3;
* null will be returned for older GDB versions.
*
* @since 4.2
*/
public String getExitCode() { return fExitCode; }
private void parse() {
MIResult[] results = getResults();
if (results == null) return;
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) {
fGroupId = ((MIConst) val).getString().trim();
}
} else if (var.equals("exit-code")) { //$NON-NLS-1$
// Available starting with GDB 7.3.
// Only present when the process properly exited
if (val instanceof MIConst) {
fExitCode = ((MIConst) val).getString().trim();
}
}
}
}
} }