From 19dadcff4893b1b2483b5445afcd76fbb3379ee3 Mon Sep 17 00:00:00 2001 From: John Cortell Date: Thu, 20 May 2010 14:25:35 +0000 Subject: [PATCH] Bug 305385: The pid of the inferior is not set pre-GDB 7.0 --- .../cdt/dsf/gdb/service/GDBProcesses.java | 14 ++++ .../mi/service/command/CommandFactory.java | 6 ++ .../mi/service/command/MIInferiorProcess.java | 63 ++++++++++++--- .../command/commands/CLIInfoProgram.java | 39 +++++++++ .../command/output/CLIInfoProgramInfo.java | 81 +++++++++++++++++++ 5 files changed, 194 insertions(+), 9 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInfoProgram.java create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/CLIInfoProgramInfo.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java index cb5be6f93fd..7cecd9377c9 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java @@ -33,6 +33,8 @@ import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext; import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.MIProcesses; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess; +import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; +import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; @@ -94,12 +96,15 @@ public class GDBProcesses extends MIProcesses { IContainerDMContext containerDmc = createContainerContext(procDmc, MIProcesses.UNIQUE_GROUP_ID); fGdb.getInferiorProcess().setContainerContext(containerDmc); + getSession().addServiceEventListener(this, null); + requestMonitor.done(); } @Override public void shutdown(RequestMonitor requestMonitor) { unregister(); + getSession().removeServiceEventListener(this); super.shutdown(requestMonitor); } @@ -291,4 +296,13 @@ public class GDBProcesses extends MIProcesses { rm.done(); } } + + /** + * @since 3.0 + */ + @DsfServiceEventHandler + public void eventDispatched(MIStoppedEvent e) { + // Get the PID of the inferior through gdb (if we don't have it already) + fGdb.getInferiorProcess().update(); + } } 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 2e84d04338a..c52bd9df109 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 @@ -30,6 +30,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.CLIAttach; import org.eclipse.cdt.dsf.mi.service.command.commands.CLICatch; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIDetach; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIExecAbort; +import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoProgram; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoSharedLibrary; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoThreads; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIJump; @@ -126,6 +127,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowAttributes; import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowFormat; import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarUpdate; import org.eclipse.cdt.dsf.mi.service.command.output.CLICatchInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoProgramInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoSharedLibraryInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoThreadsInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIThreadInfo; @@ -194,6 +196,10 @@ public class CommandFactory { return new CLIExecAbort(ctx); } + public ICommand createCLIInfoProgram(IContainerDMContext ctx) { + return new CLIInfoProgram(ctx); + } + public ICommand createCLIInfoSharedLibrary(ISymbolDMContext ctx) { return new CLIInfoSharedLibrary(ctx); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIInferiorProcess.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIInferiorProcess.java index 48df11f3d73..aa2cb6d5d16 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIInferiorProcess.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIInferiorProcess.java @@ -42,6 +42,7 @@ import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerExitedDMEvent; import org.eclipse.cdt.dsf.mi.service.command.commands.CLICommand; +import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoProgramInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIConst; import org.eclipse.cdt.dsf.mi.service.command.output.MIExecAsyncOutput; import org.eclipse.cdt.dsf.mi.service.command.output.MIGDBShowExitCodeInfo; @@ -104,13 +105,20 @@ public class MIInferiorProcess extends Process */ private int fSuppressTargetOutputCounter = 0; + /** + * Flag we use to avoid making repeated CLI 'info program' requests to get + * the PID when gdb doesn't provide the PID in the response. + */ + @ConfinedToDsfExecutor("fSession#getExecutor") + private boolean fGiveUpOnPidQuery; + @ThreadSafe Integer fExitCode = null; private State fState = State.RUNNING; @ConfinedToDsfExecutor("fSession#getExecutor") - private String fInferiorPid = null; + private String fInferiorPid; /** * Creates an inferior process object which uses the given output stream @@ -421,18 +429,23 @@ public class MIInferiorProcess extends Process public PTY getPTY() { return fPty; } - - /** - * @since 1.1 - */ + + /** + * Return the PID of this inferior, or null if not known. + * + * @since 1.1 + */ @ConfinedToDsfExecutor("fSession#getExecutor") public String getPid() { return fInferiorPid; } - - /** - * @since 1.1 - */ + + /** + * Record the PID of this inferior. The PID may not be known at the time of + * our instantiation. + * + * @since 1.1 + */ @ConfinedToDsfExecutor("fSession#getExecutor") public void setPid(String pid) { fInferiorPid = pid; @@ -511,4 +524,36 @@ public class MIInferiorProcess extends Process else if ("exit".equals(state)) { setState(State.TERMINATED); }//$NON-NLS-1$ else if ("error".equals(state)) { setState(State.STOPPED); }//$NON-NLS-1$ } + + /** + * @since 3.0 + */ + @ConfinedToDsfExecutor("fSession#getExecutor") + public void update() { + // If we don't already know the PID of the inferior, ask GDB for it. + if (getPid() == null && fContainerDMContext != null && !fGiveUpOnPidQuery) { + getCommandControlService().queueCommand( + fCommandFactory.createCLIInfoProgram(fContainerDMContext), + new DataRequestMonitor(fSession.getExecutor(), null) { + @Override + protected void handleSuccess() { + if (getPid() == null) { // check again + Long pid = getData().getPID(); + if (pid != null) { + setPid(Long.toString(pid)); + } + else { + // We made the 'program info' request to + // GDB, it gave us an answer, but it either + // doesn't provide the process PID or we + // can't make it out. No point in trying + // again. + fGiveUpOnPidQuery = true; + assert false; // investigate why this is happening + } + } + } + }); + } + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInfoProgram.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInfoProgram.java new file mode 100644 index 00000000000..79d8b602e59 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInfoProgram.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2010 QNX Software Systems, Freescale Semiconductor 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: + * Freescale Semiconductor, QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service.command.commands; + +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoProgramInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; + +/** + * @since 3.0 + */ +public class CLIInfoProgram extends CLICommand { + + public CLIInfoProgram(IContainerDMContext ctx) { + super(ctx, "info program"); //$NON-NLS-1$ + } + + @Override + public CLIInfoProgramInfo getResult(MIOutput output) { + return (CLIInfoProgramInfo)getMIInfo(output); + } + + public MIInfo getMIInfo(MIOutput out) { + MIInfo info = null; + if (out != null) { + info = new CLIInfoProgramInfo(out); + } + return info; + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/CLIInfoProgramInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/CLIInfoProgramInfo.java new file mode 100644 index 00000000000..ee04c794754 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/CLIInfoProgramInfo.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2010 QNX Software Systems, Freescale Semiconductor 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: + * Freescale Semiconductor, QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service.command.output; + +import java.util.StringTokenizer; + +/** + * @since 3.0 + */ +public class CLIInfoProgramInfo extends MIInfo { + + Long fPid; + + public CLIInfoProgramInfo(MIOutput out) { + super(out); + parse(); + } + + /** + * Return the inferior's PID reported in the output, or null if we didn't + * find it there. + */ + public Long getPID() { + return fPid; + } + + void parse() { + if (isDone()) { + MIOutput out = getMIOutput(); + MIOOBRecord[] oobs = out.getMIOOBRecords(); + for (MIOOBRecord oob : oobs) { + if (oob instanceof MIConsoleStreamOutput) { + parseLine(((MIConsoleStreamOutput)oob).getString()); + + // quit parsing output once we have everything we want out + // of it + if (fPid != null) { + break; + } + } + } + } + } + + void parseLine(String str) { + // Sample output on Windows: + // [New thread 4960.0x5d8] + // Using the running image of child thread 4960.0x5d8. + // Program stopped at 0x4012f5. + // It stopped at a breakpoint that has since been deleted. + + if (str != null && str.length() > 0) { + str = str.replace('.', ' ').trim(); + if (str.startsWith("Using")) { //$NON-NLS-1$ + StringTokenizer st = new StringTokenizer(str); + while (st.hasMoreTokens()) { + String s = st.nextToken(); + /* Not a process id if LWP is reported */ + if (s.equals("LWP")) break; //$NON-NLS-1$ + + if (Character.isDigit(s.charAt(0))) { + try { + fPid = Long.decode(s).longValue(); + break; + } catch (NumberFormatException e) { + } + } + } + } + } + } +} +