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:
parent
de790b478e
commit
c0ff399bea
7 changed files with 187 additions and 11 deletions
|
@ -59,5 +59,12 @@ public interface IGdbDebugConstants {
|
|||
*/
|
||||
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$
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -7,14 +7,22 @@
|
|||
*
|
||||
* Contributors:
|
||||
* Ericsson - Initial API and implementation
|
||||
* Marc Khouzam (Ericsson) - Display exit code in process console (Bug 402054)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.dsf.gdb.launching;
|
||||
|
||||
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.ILaunchConfiguration;
|
||||
import org.eclipse.debug.core.model.IProcess;
|
||||
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
|
||||
*
|
||||
|
@ -27,4 +35,45 @@ public class InferiorRuntimeProcess extends RuntimeProcess {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,3 +176,5 @@ LocalCDILaunchDelegate.9=Eclipse runtime does not support working directory.
|
|||
LocalCDILaunchDelegate.10=Failed to set program arguments, environment or working directory.
|
||||
ServicesLaunchSequence_0=Initializing debugger services
|
||||
ServicesLaunchSequence_1=Aborting debugger services initialization
|
||||
|
||||
InferiorRuntimeProcess_ExitValue=(exit value: {0})
|
||||
|
|
|
@ -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
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -9,6 +9,7 @@
|
|||
* QNX Software Systems - Initial API and implementation
|
||||
* Hewlett-Packard Development Company - fix for bug 109733
|
||||
* 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;
|
||||
|
@ -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.ICommandToken;
|
||||
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.launching.InferiorRuntimeProcess;
|
||||
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
|
||||
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.events.MIThreadGroupExitedEvent;
|
||||
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.MIOutput;
|
||||
|
@ -56,6 +61,8 @@ import org.eclipse.cdt.utils.pty.PTY;
|
|||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
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
|
||||
|
@ -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 {
|
||||
Query<Integer> exitCodeQuery = new Query<Integer>() {
|
||||
@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
|
||||
*/
|
||||
|
@ -486,4 +525,34 @@ public class MIInferiorProcess extends Process
|
|||
public void eventDispatched(ICommandControlShutdownDMEvent e) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -9,6 +9,7 @@
|
|||
* Wind River Systems - initial API and implementation
|
||||
* Ericsson - Version 7.0
|
||||
* 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;
|
||||
|
||||
|
@ -264,7 +265,7 @@ public class MIRunControlEventProcessor_7_0
|
|||
IContainerDMContext containerDmc = procService.createContainerContextFromGroupId(fControlDmc, groupId);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
|
|||
*
|
||||
* 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> {
|
||||
|
||||
|
|
|
@ -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
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -7,28 +7,73 @@
|
|||
*
|
||||
* Contributors:
|
||||
* 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;
|
||||
|
||||
import org.eclipse.cdt.dsf.concurrent.Immutable;
|
||||
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
|
||||
*
|
||||
*/
|
||||
@Immutable
|
||||
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) {
|
||||
super(ctx, token, null);
|
||||
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; }
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue