Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 13d5dd28411fa3406cc42ff6cdf4f2eb8c316059 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**********************************************************************
 * Copyright (c) 2007 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
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: 
 *     QNX Software Systems - Initial API and implementation
 **********************************************************************/

package org.eclipse.cdt.debug.mi.core;

import java.io.IOException;

import org.eclipse.cdt.utils.spawner.Spawner;
import org.eclipse.core.runtime.IProgressMonitor;

/**
 * @author Doug Schaefer
 */
public class CygwinMIProcessAdapter extends MIProcessAdapter {

	/**
	 * @param args
	 * @param launchTimeout
	 * @param monitor
	 * @throws IOException
	 */
	public CygwinMIProcessAdapter(String[] args, int launchTimeout,
			IProgressMonitor monitor) throws IOException {
		super(args, launchTimeout, monitor);
	}

	public void interrupt(MIInferior inferior) {
		if (fGDBProcess instanceof Spawner) {
			if (inferior.isRunning()) {
				boolean interruptedInferior = false;
				Spawner gdbSpawner = (Spawner) fGDBProcess;
				
				// Cygwin gdb 6.8 is capricious when it comes to interrupting
				// the target. MinGW and later versions of Cygwin aren't. A
				// simple CTRL-C to gdb seems to do the trick in every case.
				// Once we drop support for gdb 6.8, we should be able to ditch
				// this method and rely on the base implementation
				// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=304096#c56
				if (inferior.isRemoteInferior()) {
					// Interrupt gdb with a 'kill -SIGINT'. The reason we
					// need to send a simulated Cygwin/POSIX SIGINT to
					// Cygwin gdb is that it has special handling in the case
					// of remote debugging, as explained in the bugzilla 
					// comment above. That special handling will forward the
					// interrupt request through gdbserver to the remote
					// inferior, but the interrupt to gdb *must* be a
					// simulated Cygwin/POSIX SIGINT; a CTRL-C won't do.
					gdbSpawner.interrupt();		
				}
				else if (inferior.isAttachedInferior()) {
					// Cygwin gdb 6.8 has no support for forwarding an
					// interrupt request to the local process it has
					// attached to. That support has since been added and
					// will be available in 7.x. So, the only way to suspend the
					// attached-to inferior is to interrupt it directly.
					// The following call will take a special path in the
					// JNI code. See Java_org_eclipse_cdt_utils_spawner_Spawner_raise()
					// We don't use the Cygwin 'kill' command since we don't
					// know if the process associated with PID (the
					// inferior) is a cygwin
					// process (kill only works on cygwin programs). We also
					// can't use GenerateConsoleCtrlEvent() to send a CTRL-C
					// since that can only be used if the recipient shares a
					// console with the caller. So, we end up looking for a
					// console window associated with PID, and then we
					// fabricate keyboard events to simulate the user doing
					// a CTRL-C in that console! Crazy stuff, but it works.
					// Thing is, the PID associated with the console window
					// has to be that of the process we're trying to
					// interrupt. What that means is that in order for CDT's
					// 'suspend' button to work in an attach debug session,
					// the inferior must have been launched with its own
					// console. If you open a Windows console and type
					// 'myprogram.exe', CDT can attach to it but not suspend
					// it once it resumes it. Instead, you have to launch
					// the program by using 'start myprogram.exe'.
					interruptInferior(inferior);
					interruptedInferior = true;
				}
				else {
					// The typical case--gdb launches the inferior.
					// Interrupt gdb but with a CTRL-C. gdb (6.8) itself
					// doesn't have a handler for CTRL-C, but all processes
					// in the console
					// process group will receive the CTRL-C, and gdb
					// registers itself to catch any such events that
					// happen in the inferior. Thus it is able to determine
					// and report that the inferior has been interrupted.
					// But it's important we don't interrupt Cygwin gdb with
					// a 'kill' since that will only reach gdb, and gdb
					// won't forward the request on to the inferior. See
					// bugzilla comment referenced above for details.
					gdbSpawner.interruptCTRLC(); 
				}
				
				waitForInterrupt(inferior);

				// If we are still running try to interrupt the inferior (unless we
				// already tried that above)
				if (inferior.isRunning() && inferior.getInferiorPID() > 0 && !interruptedInferior) {
					// lets try something else.
					interruptInferior(inferior);
				}
			}
		}
			
	}
	
}

Back to the top