Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java @ 3944:35c656d0b685
7090654: nightly failures after 7086585
Reviewed-by: kvn
author | never |
---|---|
date | Wed, 14 Sep 2011 13:57:32 -0700 |
parents | f6f3bb0ee072 |
children | f08d439fab8c |
rev | line source |
---|---|
0 | 1 /* |
3939 | 2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 package sun.jvm.hotspot; | |
26 | |
27 import java.io.PrintStream; | |
28 import java.net.*; | |
29 import java.rmi.*; | |
30 import sun.jvm.hotspot.debugger.*; | |
31 import sun.jvm.hotspot.debugger.proc.*; | |
32 import sun.jvm.hotspot.debugger.remote.*; | |
33 import sun.jvm.hotspot.debugger.windbg.*; | |
34 import sun.jvm.hotspot.debugger.linux.*; | |
35 import sun.jvm.hotspot.memory.*; | |
36 import sun.jvm.hotspot.oops.*; | |
37 import sun.jvm.hotspot.runtime.*; | |
38 import sun.jvm.hotspot.types.*; | |
39 import sun.jvm.hotspot.utilities.*; | |
40 | |
41 /** <P> This class wraps much of the basic functionality and is the | |
42 * highest-level factory for VM data structures. It makes it simple | |
43 * to start up the debugging system. </P> | |
44 * | |
45 * <P> FIXME: need to add a way to configure the paths to dbx and the | |
46 * DSO from the outside. However, this should work for now for | |
47 * internal use. </P> | |
48 * | |
49 * <P> FIXME: especially with the addition of remote debugging, this | |
50 * has turned into a mess; needs rethinking. </P> | |
51 */ | |
52 | |
53 public class HotSpotAgent { | |
54 private JVMDebugger debugger; | |
55 private MachineDescription machDesc; | |
56 private TypeDataBase db; | |
57 | |
58 private String os; | |
59 private String cpu; | |
60 private String fileSep; | |
61 | |
62 // The system can work in several ways: | |
63 // - Attaching to local process | |
64 // - Attaching to local core file | |
65 // - Connecting to remote debug server | |
66 // - Starting debug server for process | |
67 // - Starting debug server for core file | |
68 | |
69 // These are options for the "client" side of things | |
70 private static final int PROCESS_MODE = 0; | |
71 private static final int CORE_FILE_MODE = 1; | |
72 private static final int REMOTE_MODE = 2; | |
73 private int startupMode; | |
74 | |
75 // This indicates whether we are really starting a server or not | |
76 private boolean isServer; | |
77 | |
78 // All possible required information for connecting | |
79 private int pid; | |
80 private String javaExecutableName; | |
81 private String coreFileName; | |
82 private String debugServerID; | |
83 | |
84 // All needed information for server side | |
85 private String serverID; | |
86 | |
87 private String[] jvmLibNames; | |
88 | |
89 // FIXME: make these configurable, i.e., via a dotfile; also | |
90 // consider searching within the JDK from which this Java executable | |
91 // comes to find them | |
92 private static final String defaultDbxPathPrefix = "/net/jano.sfbay/export/disk05/hotspot/sa"; | |
93 private static final String defaultDbxSvcAgentDSOPathPrefix = "/net/jano.sfbay/export/disk05/hotspot/sa"; | |
94 | |
95 static void showUsage() { | |
96 System.out.println(" You can also pass these -D options to java to specify where to find dbx and the \n" + | |
97 " Serviceability Agent plugin for dbx:"); | |
98 System.out.println(" -DdbxPathName=<path-to-dbx-executable>\n" + | |
99 " Default is derived from dbxPathPrefix"); | |
100 System.out.println(" or"); | |
101 System.out.println(" -DdbxPathPrefix=<xxx>\n" + | |
102 " where xxx is the path name of a dir structure that contains:\n" + | |
103 " <os>/<arch>/bin/dbx\n" + | |
104 " The default is " + defaultDbxPathPrefix); | |
105 System.out.println(" and"); | |
106 System.out.println(" -DdbxSvcAgentDSOPathName=<path-to-dbx-serviceability-agent-module>\n" + | |
107 " Default is determined from dbxSvcAgentDSOPathPrefix"); | |
108 System.out.println(" or"); | |
109 System.out.println(" -DdbxSvcAgentDSOPathPrefix=<xxx>\n" + | |
110 " where xxx is the pathname of a dir structure that contains:\n" + | |
111 " <os>/<arch>/bin/lib/libsvc_agent_dbx.so\n" + | |
112 " The default is " + defaultDbxSvcAgentDSOPathPrefix); | |
113 } | |
114 | |
115 public HotSpotAgent() { | |
116 // for non-server add shutdown hook to clean-up debugger in case | |
117 // of forced exit. For remote server, shutdown hook is added by | |
118 // DebugServer. | |
119 Runtime.getRuntime().addShutdownHook(new java.lang.Thread( | |
120 new Runnable() { | |
121 public void run() { | |
122 synchronized (HotSpotAgent.this) { | |
123 if (!isServer) { | |
124 detach(); | |
125 } | |
126 } | |
127 } | |
128 })); | |
129 } | |
130 | |
131 //-------------------------------------------------------------------------------- | |
132 // Accessors (once the system is set up) | |
133 // | |
134 | |
135 public synchronized Debugger getDebugger() { | |
136 return debugger; | |
137 } | |
138 | |
139 public synchronized TypeDataBase getTypeDataBase() { | |
140 return db; | |
141 } | |
142 | |
143 //-------------------------------------------------------------------------------- | |
144 // Client-side operations | |
145 // | |
146 | |
147 /** This attaches to a process running on the local machine. */ | |
148 public synchronized void attach(int processID) | |
149 throws DebuggerException { | |
150 if (debugger != null) { | |
151 throw new DebuggerException("Already attached"); | |
152 } | |
153 pid = processID; | |
154 startupMode = PROCESS_MODE; | |
155 isServer = false; | |
156 go(); | |
157 } | |
158 | |
159 /** This opens a core file on the local machine */ | |
160 public synchronized void attach(String javaExecutableName, String coreFileName) | |
161 throws DebuggerException { | |
162 if (debugger != null) { | |
163 throw new DebuggerException("Already attached"); | |
164 } | |
165 if ((javaExecutableName == null) || (coreFileName == null)) { | |
166 throw new DebuggerException("Both the core file name and Java executable name must be specified"); | |
167 } | |
168 this.javaExecutableName = javaExecutableName; | |
169 this.coreFileName = coreFileName; | |
170 startupMode = CORE_FILE_MODE; | |
171 isServer = false; | |
172 go(); | |
173 } | |
174 | |
175 /** This attaches to a "debug server" on a remote machine; this | |
176 remote server has already attached to a process or opened a | |
177 core file and is waiting for RMI calls on the Debugger object to | |
178 come in. */ | |
179 public synchronized void attach(String remoteServerID) | |
180 throws DebuggerException { | |
181 if (debugger != null) { | |
182 throw new DebuggerException("Already attached to a process"); | |
183 } | |
184 if (remoteServerID == null) { | |
185 throw new DebuggerException("Debug server id must be specified"); | |
186 } | |
187 | |
188 debugServerID = remoteServerID; | |
189 startupMode = REMOTE_MODE; | |
190 isServer = false; | |
191 go(); | |
192 } | |
193 | |
194 /** This should only be called by the user on the client machine, | |
195 not the server machine */ | |
196 public synchronized boolean detach() throws DebuggerException { | |
197 if (isServer) { | |
198 throw new DebuggerException("Should not call detach() for server configuration"); | |
199 } | |
200 return detachInternal(); | |
201 } | |
202 | |
203 //-------------------------------------------------------------------------------- | |
204 // Server-side operations | |
205 // | |
206 | |
207 /** This attaches to a process running on the local machine and | |
208 starts a debug server, allowing remote machines to connect and | |
209 examine this process. Uses specified name to uniquely identify a | |
210 specific debuggee on the server */ | |
211 public synchronized void startServer(int processID, String uniqueID) { | |
212 if (debugger != null) { | |
213 throw new DebuggerException("Already attached"); | |
214 } | |
215 pid = processID; | |
216 startupMode = PROCESS_MODE; | |
217 isServer = true; | |
218 serverID = uniqueID; | |
219 go(); | |
220 } | |
221 | |
222 /** This attaches to a process running on the local machine and | |
223 starts a debug server, allowing remote machines to connect and | |
224 examine this process. */ | |
225 public synchronized void startServer(int processID) | |
226 throws DebuggerException { | |
227 startServer(processID, null); | |
228 } | |
229 | |
230 /** This opens a core file on the local machine and starts a debug | |
231 server, allowing remote machines to connect and examine this | |
232 core file. Uses supplied uniqueID to uniquely identify a specific | |
233 debugee */ | |
234 public synchronized void startServer(String javaExecutableName, | |
235 String coreFileName, | |
236 String uniqueID) { | |
237 if (debugger != null) { | |
238 throw new DebuggerException("Already attached"); | |
239 } | |
240 if ((javaExecutableName == null) || (coreFileName == null)) { | |
241 throw new DebuggerException("Both the core file name and Java executable name must be specified"); | |
242 } | |
243 this.javaExecutableName = javaExecutableName; | |
244 this.coreFileName = coreFileName; | |
245 startupMode = CORE_FILE_MODE; | |
246 isServer = true; | |
247 serverID = uniqueID; | |
248 go(); | |
249 } | |
250 | |
251 /** This opens a core file on the local machine and starts a debug | |
252 server, allowing remote machines to connect and examine this | |
253 core file. */ | |
254 public synchronized void startServer(String javaExecutableName, String coreFileName) | |
255 throws DebuggerException { | |
256 startServer(javaExecutableName, coreFileName, null); | |
257 } | |
258 | |
259 /** This may only be called on the server side after startServer() | |
260 has been called */ | |
261 public synchronized boolean shutdownServer() throws DebuggerException { | |
262 if (!isServer) { | |
263 throw new DebuggerException("Should not call shutdownServer() for client configuration"); | |
264 } | |
265 return detachInternal(); | |
266 } | |
267 | |
268 | |
269 //-------------------------------------------------------------------------------- | |
270 // Internals only below this point | |
271 // | |
272 | |
273 private boolean detachInternal() { | |
274 if (debugger == null) { | |
275 return false; | |
276 } | |
277 boolean retval = true; | |
278 if (!isServer) { | |
279 VM.shutdown(); | |
280 } | |
281 // We must not call detach() if we are a client and are connected | |
282 // to a remote debugger | |
283 Debugger dbg = null; | |
284 DebuggerException ex = null; | |
285 if (isServer) { | |
286 try { | |
287 RMIHelper.unbind(serverID); | |
288 } | |
289 catch (DebuggerException de) { | |
290 ex = de; | |
291 } | |
292 dbg = debugger; | |
293 } else { | |
294 if (startupMode != REMOTE_MODE) { | |
295 dbg = debugger; | |
296 } | |
297 } | |
298 if (dbg != null) { | |
299 retval = dbg.detach(); | |
300 } | |
301 | |
302 debugger = null; | |
303 machDesc = null; | |
304 db = null; | |
305 if (ex != null) { | |
306 throw(ex); | |
307 } | |
308 return retval; | |
309 } | |
310 | |
311 private void go() { | |
312 setupDebugger(); | |
313 setupVM(); | |
314 } | |
315 | |
316 private void setupDebugger() { | |
317 if (startupMode != REMOTE_MODE) { | |
318 // | |
319 // Local mode (client attaching to local process or setting up | |
320 // server, but not client attaching to server) | |
321 // | |
322 | |
323 try { | |
324 os = PlatformInfo.getOS(); | |
325 cpu = PlatformInfo.getCPU(); | |
326 } | |
327 catch (UnsupportedPlatformException e) { | |
328 throw new DebuggerException(e); | |
329 } | |
330 fileSep = System.getProperty("file.separator"); | |
331 | |
332 if (os.equals("solaris")) { | |
333 setupDebuggerSolaris(); | |
334 } else if (os.equals("win32")) { | |
335 setupDebuggerWin32(); | |
336 } else if (os.equals("linux")) { | |
337 setupDebuggerLinux(); | |
338 } else { | |
339 // Add support for more operating systems here | |
340 throw new DebuggerException("Operating system " + os + " not yet supported"); | |
341 } | |
342 | |
343 if (isServer) { | |
344 RemoteDebuggerServer remote = null; | |
345 try { | |
346 remote = new RemoteDebuggerServer(debugger); | |
347 } | |
348 catch (RemoteException rem) { | |
349 throw new DebuggerException(rem); | |
350 } | |
351 RMIHelper.rebind(serverID, remote); | |
352 } | |
353 } else { | |
354 // | |
355 // Remote mode (client attaching to server) | |
356 // | |
357 | |
358 // Create and install a security manager | |
359 | |
360 // FIXME: currently commented out because we were having | |
361 // security problems since we're "in the sun.* hierarchy" here. | |
362 // Perhaps a permissive policy file would work around this. In | |
363 // the long run, will probably have to move into com.sun.*. | |
364 | |
365 // if (System.getSecurityManager() == null) { | |
366 // System.setSecurityManager(new RMISecurityManager()); | |
367 // } | |
368 | |
369 connectRemoteDebugger(); | |
370 } | |
371 } | |
372 | |
373 private void setupVM() { | |
374 // We need to instantiate a HotSpotTypeDataBase on both the client | |
375 // and server machine. On the server it is only currently used to | |
376 // configure the Java primitive type sizes (which we should | |
377 // consider making constant). On the client it is used to | |
378 // configure the VM. | |
379 | |
380 try { | |
381 if (os.equals("solaris")) { | |
382 db = new HotSpotTypeDataBase(machDesc, | |
383 new HotSpotSolarisVtblAccess(debugger, jvmLibNames), | |
384 debugger, jvmLibNames); | |
385 } else if (os.equals("win32")) { | |
386 db = new HotSpotTypeDataBase(machDesc, | |
387 new Win32VtblAccess(debugger, jvmLibNames), | |
388 debugger, jvmLibNames); | |
389 } else if (os.equals("linux")) { | |
390 db = new HotSpotTypeDataBase(machDesc, | |
391 new LinuxVtblAccess(debugger, jvmLibNames), | |
392 debugger, jvmLibNames); | |
393 } else { | |
394 throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)"); | |
395 } | |
396 } | |
397 catch (NoSuchSymbolException e) { | |
398 throw new DebuggerException("Doesn't appear to be a HotSpot VM (could not find symbol \"" + | |
399 e.getSymbol() + "\" in remote process)"); | |
400 } | |
401 | |
402 if (startupMode != REMOTE_MODE) { | |
403 // Configure the debugger with the primitive type sizes just obtained from the VM | |
404 debugger.configureJavaPrimitiveTypeSizes(db.getJBooleanType().getSize(), | |
405 db.getJByteType().getSize(), | |
406 db.getJCharType().getSize(), | |
407 db.getJDoubleType().getSize(), | |
408 db.getJFloatType().getSize(), | |
409 db.getJIntType().getSize(), | |
410 db.getJLongType().getSize(), | |
411 db.getJShortType().getSize()); | |
412 } | |
413 | |
414 if (!isServer) { | |
415 // Do not initialize the VM on the server (unnecessary, since it's | |
416 // instantiated on the client) | |
417 try { | |
418 VM.initialize(db, debugger); | |
419 } catch (DebuggerException e) { | |
420 throw (e); | |
421 } catch (Exception e) { | |
422 throw new DebuggerException(e); | |
423 } | |
424 } | |
425 } | |
426 | |
427 //-------------------------------------------------------------------------------- | |
428 // OS-specific debugger setup/connect routines | |
429 // | |
430 | |
431 // | |
432 // Solaris | |
433 // | |
434 | |
435 private void setupDebuggerSolaris() { | |
436 setupJVMLibNamesSolaris(); | |
3939 | 437 ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true); |
438 debugger = dbg; | |
439 attachDebugger(); | |
0 | 440 |
3939 | 441 // Set up CPU-dependent stuff |
442 if (cpu.equals("x86")) { | |
443 machDesc = new MachineDescriptionIntelX86(); | |
444 } else if (cpu.equals("sparc")) { | |
445 int addressSize = dbg.getRemoteProcessAddressSize(); | |
446 if (addressSize == -1) { | |
447 throw new DebuggerException("Error occurred while trying to determine the remote process's " + | |
448 "address size"); | |
0 | 449 } |
450 | |
3939 | 451 if (addressSize == 32) { |
452 machDesc = new MachineDescriptionSPARC32Bit(); | |
453 } else if (addressSize == 64) { | |
454 machDesc = new MachineDescriptionSPARC64Bit(); | |
0 | 455 } else { |
3939 | 456 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); |
0 | 457 } |
3939 | 458 } else if (cpu.equals("amd64")) { |
459 machDesc = new MachineDescriptionAMD64(); | |
460 } else { | |
461 throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64"); | |
462 } | |
0 | 463 |
3939 | 464 dbg.setMachineDescription(machDesc); |
465 return; | |
0 | 466 } |
467 | |
468 private void connectRemoteDebugger() throws DebuggerException { | |
469 RemoteDebugger remote = | |
470 (RemoteDebugger) RMIHelper.lookup(debugServerID); | |
471 debugger = new RemoteDebuggerClient(remote); | |
472 machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription(); | |
473 os = debugger.getOS(); | |
474 if (os.equals("solaris")) { | |
475 setupJVMLibNamesSolaris(); | |
476 } else if (os.equals("win32")) { | |
477 setupJVMLibNamesWin32(); | |
478 } else if (os.equals("linux")) { | |
479 setupJVMLibNamesLinux(); | |
480 } else { | |
481 throw new RuntimeException("Unknown OS type"); | |
482 } | |
483 | |
484 cpu = debugger.getCPU(); | |
485 } | |
486 | |
487 private void setupJVMLibNamesSolaris() { | |
488 jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" }; | |
489 } | |
490 | |
491 // | |
492 // Win32 | |
493 // | |
494 | |
495 private void setupDebuggerWin32() { | |
496 setupJVMLibNamesWin32(); | |
497 | |
498 if (cpu.equals("x86")) { | |
499 machDesc = new MachineDescriptionIntelX86(); | |
500 } else if (cpu.equals("amd64")) { | |
501 machDesc = new MachineDescriptionAMD64(); | |
502 } else if (cpu.equals("ia64")) { | |
503 machDesc = new MachineDescriptionIA64(); | |
504 } else { | |
505 throw new DebuggerException("Win32 supported under x86, amd64 and ia64 only"); | |
506 } | |
507 | |
508 // Note we do not use a cache for the local debugger in server | |
509 // mode; it will be taken care of on the client side (once remote | |
510 // debugging is implemented). | |
511 | |
3939 | 512 debugger = new WindbgDebuggerLocal(machDesc, !isServer); |
0 | 513 |
514 attachDebugger(); | |
515 | |
516 // FIXME: add support for server mode | |
517 } | |
518 | |
519 private void setupJVMLibNamesWin32() { | |
520 jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" }; | |
521 } | |
522 | |
523 // | |
524 // Linux | |
525 // | |
526 | |
527 private void setupDebuggerLinux() { | |
528 setupJVMLibNamesLinux(); | |
529 | |
530 if (cpu.equals("x86")) { | |
531 machDesc = new MachineDescriptionIntelX86(); | |
532 } else if (cpu.equals("ia64")) { | |
533 machDesc = new MachineDescriptionIA64(); | |
534 } else if (cpu.equals("amd64")) { | |
535 machDesc = new MachineDescriptionAMD64(); | |
536 } else if (cpu.equals("sparc")) { | |
537 if (LinuxDebuggerLocal.getAddressSize()==8) { | |
538 machDesc = new MachineDescriptionSPARC64Bit(); | |
539 } else { | |
540 machDesc = new MachineDescriptionSPARC32Bit(); | |
541 } | |
542 } else { | |
543 throw new DebuggerException("Linux only supported on x86/ia64/amd64/sparc/sparc64"); | |
544 } | |
545 | |
546 LinuxDebuggerLocal dbg = | |
547 new LinuxDebuggerLocal(machDesc, !isServer); | |
548 debugger = dbg; | |
549 | |
550 attachDebugger(); | |
551 } | |
552 | |
553 private void setupJVMLibNamesLinux() { | |
554 jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; | |
555 } | |
556 | |
557 /** Convenience routine which should be called by per-platform | |
558 debugger setup. Should not be called when startupMode is | |
559 REMOTE_MODE. */ | |
560 private void attachDebugger() { | |
561 if (startupMode == PROCESS_MODE) { | |
562 debugger.attach(pid); | |
563 } else if (startupMode == CORE_FILE_MODE) { | |
564 debugger.attach(javaExecutableName, coreFileName); | |
565 } else { | |
566 throw new DebuggerException("Should not call attach() for startupMode == " + startupMode); | |
567 } | |
568 } | |
569 } |