|
1 /* |
|
2 * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
21 * have any questions. |
|
22 */ |
|
23 |
|
24 /* |
|
25 * Note 1: JITDebug.java is no longer a standalone regression test, |
|
26 * due to chronic test failures on win32 platforms. When testing, |
|
27 * use the wrapper script (JITDebug.sh) instead, which will in turn |
|
28 * invoke this program. |
|
29 * |
|
30 * The problems are related to inconsistent use of "SystemRoot" |
|
31 * versus "SYSTEMROOT" environment variables in different win32 O/S |
|
32 * installations. Refer to the Comments and Evaluation on bugs |
|
33 * 4522770 and 4461673 for more information. |
|
34 * |
|
35 * Undefined SystemRoot in a win32 environment causes the O/S socket() |
|
36 * layer to fail with WSAEPROVIDERFAILEDINIT. The workaround used by |
|
37 * JITDebug.sh and JITDebug.java is to select the dt_shmem transport |
|
38 * on any win32 platform where SystemRoot is not found. |
|
39 * |
|
40 * Note 2: What seems to be an excessive use of System.xxx.flush(); |
|
41 * is actually necessary to combat lost output on win32 systems. |
|
42 * |
|
43 * @t e s t |
|
44 * @bug 4291701 4376819 4422312 4522770 |
|
45 * @summary Test JIT debugging - |
|
46 * assure that launching on uncaught exception works |
|
47 * |
|
48 * @author Robert Field |
|
49 * @run main/othervm JITDebug |
|
50 */ |
|
51 |
|
52 import com.sun.jdi.*; |
|
53 import com.sun.jdi.connect.*; |
|
54 import java.util.*; |
|
55 import java.io.*; |
|
56 |
|
57 /* |
|
58 * This class implements three separate small programs, each |
|
59 * of which (directly or indirectly) invokes the next. These |
|
60 * programs are: |
|
61 * test launcher - |
|
62 * Runs the debug target. It exists to work around a |
|
63 * bug in the test tools which do not allow quoted spaces |
|
64 * in command lines. It launchs the debug target in |
|
65 * such a way that when it encounters an uncaught exception |
|
66 * it (in turn) will launch the trivial debugger. |
|
67 * debug target - |
|
68 * A one line program which throws an uncaught exception. |
|
69 * trivial debugger - |
|
70 * A debugger which attachs to the debug target and shuts |
|
71 * it down with a zero exit code. |
|
72 * These programs are differentiated by their command line arguments: |
|
73 * test launcher - (no args) |
|
74 * debug target - ("TARGET") |
|
75 * trivial debugger - ("DEBUGGER", host and port) |
|
76 */ |
|
77 public class JITDebug { |
|
78 |
|
79 public static void main(String[] args) { |
|
80 if (!new JITDebug().parseArgs(args)) { |
|
81 throw new RuntimeException("Unexpected command line arguments: " |
|
82 + args); |
|
83 } |
|
84 } |
|
85 |
|
86 boolean parseArgs(String[] args) { |
|
87 switch (args.length) { |
|
88 case 0: |
|
89 testLaunch(); |
|
90 return true; |
|
91 case 1: |
|
92 if (args[0].equals("TARGET")) { |
|
93 debugTarget(); |
|
94 return true; |
|
95 } else { |
|
96 return false; |
|
97 } |
|
98 case 3: |
|
99 if (args[0].equals("DEBUGGER")) { |
|
100 trivialDebugger(args[2]); |
|
101 return true; |
|
102 } else { |
|
103 return false; |
|
104 } |
|
105 default: |
|
106 return false; |
|
107 } |
|
108 } |
|
109 |
|
110 void testLaunch() { |
|
111 class DisplayOutput extends Thread { |
|
112 InputStream in; |
|
113 |
|
114 DisplayOutput(InputStream in) { |
|
115 this.in = in; |
|
116 } |
|
117 |
|
118 public void run() { |
|
119 try { |
|
120 transfer(); |
|
121 } catch (IOException exc) { |
|
122 new RuntimeException("Unexpected exception: " + exc); |
|
123 } |
|
124 } |
|
125 |
|
126 void transfer() throws IOException { |
|
127 int ch; |
|
128 while ((ch = in.read()) != -1) { |
|
129 System.out.print((char)ch); |
|
130 } |
|
131 in.close(); |
|
132 } |
|
133 } |
|
134 String transportMethod = System.getProperty("TRANSPORT_METHOD"); |
|
135 if (transportMethod == null) { |
|
136 transportMethod = "dt_socket"; //Default to socket transport. |
|
137 } |
|
138 String javaExe = System.getProperty("java.home") + |
|
139 File.separator + "bin" + File.separator +"java"; |
|
140 List largs = new ArrayList(); |
|
141 largs.add(javaExe); |
|
142 largs.add("-agentlib:jdwp=transport=" + transportMethod + ",server=y,onuncaught=y," + |
|
143 "launch=" + |
|
144 javaExe + " -DTRANSPORT_METHOD=" + transportMethod + " " + |
|
145 this.getClass().getName() + " DEBUGGER "); |
|
146 largs.add("JITDebug"); |
|
147 largs.add("TARGET"); |
|
148 System.out.println("Launching: " + largs); |
|
149 String[] sargs = (String[])largs.toArray(new String[largs.size()]); |
|
150 Runtime rt = Runtime.getRuntime(); |
|
151 try { |
|
152 Process proc = rt.exec(VMConnection.insertDebuggeeVMOptions(sargs)); |
|
153 DisplayOutput inThread = new DisplayOutput(proc.getInputStream()); |
|
154 DisplayOutput erThread = new DisplayOutput(proc.getErrorStream()); |
|
155 inThread.start(); // transfer all in&err |
|
156 erThread.start(); |
|
157 inThread.join(); // make sure they are done |
|
158 erThread.join(); |
|
159 int exitValue = proc.waitFor(); |
|
160 if (exitValue != 0) { |
|
161 throw new RuntimeException("Failure exit status: " + |
|
162 exitValue); |
|
163 } |
|
164 } catch (Exception exc) { |
|
165 throw new RuntimeException("Unexpected exception: " + exc); |
|
166 } |
|
167 System.out.println("JIT Debugging test PASSED"); |
|
168 } |
|
169 |
|
170 void displayOutput(InputStream in) throws IOException { |
|
171 |
|
172 } |
|
173 |
|
174 |
|
175 // Target VM code |
|
176 void debugTarget() { |
|
177 System.out.flush(); |
|
178 System.out.println("trigger onuncaught launch"); |
|
179 System.out.flush(); |
|
180 throw new RuntimeException("Start-up onuncaught handling"); |
|
181 } |
|
182 |
|
183 void trivialDebugger(String transportAddress) { |
|
184 System.out.println("trivial debugger started"); |
|
185 String transportMethod = System.getProperty("TRANSPORT_METHOD"); |
|
186 String connectorName = null; |
|
187 if ("dt_shmem".equals(transportMethod)) { |
|
188 connectorName = "com.sun.jdi.SharedMemoryAttach"; |
|
189 } else if ("dt_socket".equals(transportMethod)) { |
|
190 connectorName = "com.sun.jdi.SocketAttach"; |
|
191 } else { |
|
192 System.err.flush(); |
|
193 System.err.println("Unknown transportMethod: " + transportMethod + " - hanging"); |
|
194 System.err.flush(); |
|
195 hang(); |
|
196 } |
|
197 List conns = Bootstrap.virtualMachineManager().attachingConnectors(); |
|
198 for (Iterator it = conns.iterator(); it.hasNext(); ) { |
|
199 AttachingConnector conn = (AttachingConnector)it.next(); |
|
200 if (conn.name().equals(connectorName)) { |
|
201 doAttach(connectorName, conn, transportAddress); |
|
202 return; |
|
203 } |
|
204 } |
|
205 System.err.flush(); |
|
206 System.err.println("No attaching connector matching: " + connectorName + " - hanging"); |
|
207 System.err.flush(); |
|
208 hang(); |
|
209 } |
|
210 |
|
211 void doAttach(String connectorName, AttachingConnector conn, String transportAddress) { |
|
212 Map connArgs = conn.defaultArguments(); |
|
213 if ("com.sun.jdi.SharedMemoryAttach".equals(connectorName)) { |
|
214 Connector.Argument portArg = (Connector.Argument)connArgs.get("name"); |
|
215 portArg.setValue(transportAddress); |
|
216 } else { |
|
217 Connector.Argument portArg = (Connector.Argument)connArgs.get("port"); |
|
218 portArg.setValue(transportAddress); |
|
219 } |
|
220 try { |
|
221 VirtualMachine vm = conn.attach(connArgs); |
|
222 System.out.println("attached to: " + transportAddress); |
|
223 vm.exit(0); // we are happy - terminate VM with no error |
|
224 System.out.println("we are happy - terminated VM with no error"); |
|
225 } catch (Exception exc) { |
|
226 System.err.flush(); |
|
227 System.err.println("Exception: " + exc + " - hanging"); |
|
228 System.err.flush(); |
|
229 hang(); |
|
230 } |
|
231 } |
|
232 |
|
233 /** Hang so that test fails */ |
|
234 void hang() { |
|
235 try { |
|
236 // ten minute nap |
|
237 Thread.currentThread().sleep(10 * 60 * 1000); |
|
238 } catch (InterruptedException exc) { |
|
239 // shouldn't happen |
|
240 } |
|
241 } |
|
242 } |