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