Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java @ 1552:c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
Summary: Change all the Sun copyrights to Oracle copyright
Reviewed-by: ohair
author | trims |
---|---|
date | Thu, 27 May 2010 19:08:38 -0700 |
parents | a61af66fc99e |
children | f6f3bb0ee072 |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2002, 2006, 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.bugspot; | |
26 | |
27 import java.io.PrintStream; | |
28 import java.net.*; | |
29 import java.rmi.*; | |
30 import sun.jvm.hotspot.*; | |
31 import sun.jvm.hotspot.debugger.*; | |
32 import sun.jvm.hotspot.debugger.dbx.*; | |
33 import sun.jvm.hotspot.debugger.proc.*; | |
34 import sun.jvm.hotspot.debugger.cdbg.*; | |
35 import sun.jvm.hotspot.debugger.win32.*; | |
36 import sun.jvm.hotspot.debugger.windbg.*; | |
37 import sun.jvm.hotspot.debugger.linux.*; | |
38 import sun.jvm.hotspot.debugger.sparc.*; | |
39 import sun.jvm.hotspot.debugger.remote.*; | |
40 import sun.jvm.hotspot.livejvm.*; | |
41 import sun.jvm.hotspot.memory.*; | |
42 import sun.jvm.hotspot.oops.*; | |
43 import sun.jvm.hotspot.runtime.*; | |
44 import sun.jvm.hotspot.types.*; | |
45 import sun.jvm.hotspot.utilities.*; | |
46 | |
47 /** <P> This class wraps the basic functionality for connecting to the | |
48 * target process or debug server. It makes it simple to start up the | |
49 * debugging system. </P> | |
50 * | |
51 * <P> This agent (as compared to the HotSpotAgent) can connect to | |
52 * and interact with arbitrary processes. If the target process | |
53 * happens to be a HotSpot JVM, the Java debugging features of the | |
54 * Serviceability Agent are enabled. Further, if the Serviceability | |
55 * Agent's JVMDI module is loaded into the target VM, interaction | |
56 * with the live Java program is possible, specifically the catching | |
57 * of exceptions and setting of breakpoints. </P> | |
58 * | |
59 * <P> The BugSpot debugger requires that the underlying Debugger | |
60 * support C/C++ debugging via the CDebugger interface. </P> | |
61 * | |
62 * <P> FIXME: need to add a way to configure the paths to dbx and the | |
63 * DSO from the outside. However, this should work for now for | |
64 * internal use. </P> | |
65 * | |
66 * <P> FIXME: especially with the addition of remote debugging, this | |
67 * has turned into a mess; needs rethinking. </P> */ | |
68 | |
69 public class BugSpotAgent { | |
70 | |
71 private JVMDebugger debugger; | |
72 private MachineDescription machDesc; | |
73 private TypeDataBase db; | |
74 | |
75 private String os; | |
76 private String cpu; | |
77 private String fileSep; | |
78 | |
79 // The system can work in several ways: | |
80 // - Attaching to local process | |
81 // - Attaching to local core file | |
82 // - Connecting to remote debug server | |
83 // - Starting debug server for process | |
84 // - Starting debug server for core file | |
85 | |
86 // These are options for the "client" side of things | |
87 private static final int PROCESS_MODE = 0; | |
88 private static final int CORE_FILE_MODE = 1; | |
89 private static final int REMOTE_MODE = 2; | |
90 private int startupMode; | |
91 | |
92 // This indicates whether we are really starting a server or not | |
93 private boolean isServer; | |
94 | |
95 // All possible required information for connecting | |
96 private int pid; | |
97 private String executableName; | |
98 private String coreFileName; | |
99 private String debugServerID; | |
100 | |
101 // All needed information for server side | |
102 private String serverID; | |
103 | |
104 // Indicates whether we are attached to a HotSpot JVM or not | |
105 private boolean javaMode; | |
106 | |
107 // Indicates whether we have process control over a live HotSpot JVM | |
108 // or not; non-null if so. | |
109 private ServiceabilityAgentJVMDIModule jvmdi; | |
110 // While handling C breakpoints interactivity with the Java program | |
111 // is forbidden. Too many invariants are broken while the target is | |
112 // stopped at a C breakpoint to risk making JVMDI calls. | |
113 private boolean javaInteractionDisabled; | |
114 | |
115 private String[] jvmLibNames; | |
116 private String[] saLibNames; | |
117 | |
118 // FIXME: make these configurable, i.e., via a dotfile; also | |
119 // consider searching within the JDK from which this Java executable | |
120 // comes to find them | |
121 private static final String defaultDbxPathPrefix = "/net/jano.eng/export/disk05/hotspot/sa"; | |
122 private static final String defaultDbxSvcAgentDSOPathPrefix = "/net/jano.eng/export/disk05/hotspot/sa"; | |
123 | |
124 private static final boolean DEBUG; | |
125 static { | |
126 DEBUG = System.getProperty("sun.jvm.hotspot.bugspot.BugSpotAgent.DEBUG") | |
127 != null; | |
128 } | |
129 | |
130 static void debugPrintln(String str) { | |
131 if (DEBUG) { | |
132 System.err.println(str); | |
133 } | |
134 } | |
135 | |
136 static void showUsage() { | |
137 System.out.println(" You can also pass these -D options to java to specify where to find dbx and the \n" + | |
138 " Serviceability Agent plugin for dbx:"); | |
139 System.out.println(" -DdbxPathName=<path-to-dbx-executable>\n" + | |
140 " Default is derived from dbxPathPrefix"); | |
141 System.out.println(" or"); | |
142 System.out.println(" -DdbxPathPrefix=<xxx>\n" + | |
143 " where xxx is the path name of a dir structure that contains:\n" + | |
144 " <os>/<arch>/bin/dbx\n" + | |
145 " The default is " + defaultDbxPathPrefix); | |
146 System.out.println(" and"); | |
147 System.out.println(" -DdbxSvcAgentDSOPathName=<path-to-dbx-serviceability-agent-module>\n" + | |
148 " Default is determined from dbxSvcAgentDSOPathPrefix"); | |
149 System.out.println(" or"); | |
150 System.out.println(" -DdbxSvcAgentDSOPathPrefix=<xxx>\n" + | |
151 " where xxx is the pathname of a dir structure that contains:\n" + | |
152 " <os>/<arch>/bin/lib/libsvc_agent_dbx.so\n" + | |
153 " The default is " + defaultDbxSvcAgentDSOPathPrefix); | |
154 } | |
155 | |
156 public BugSpotAgent() { | |
157 // for non-server add shutdown hook to clean-up debugger in case | |
158 // of forced exit. For remote server, shutdown hook is added by | |
159 // DebugServer. | |
160 Runtime.getRuntime().addShutdownHook(new java.lang.Thread( | |
161 new Runnable() { | |
162 public void run() { | |
163 synchronized (BugSpotAgent.this) { | |
164 if (!isServer) { | |
165 detach(); | |
166 } | |
167 } | |
168 } | |
169 })); | |
170 } | |
171 | |
172 //-------------------------------------------------------------------------------- | |
173 // Accessors (once the system is set up) | |
174 // | |
175 | |
176 public synchronized Debugger getDebugger() { | |
177 return debugger; | |
178 } | |
179 | |
180 public synchronized CDebugger getCDebugger() { | |
181 return getDebugger().getCDebugger(); | |
182 } | |
183 | |
184 public synchronized ProcessControl getProcessControl() { | |
185 return getCDebugger().getProcessControl(); | |
186 } | |
187 | |
188 public synchronized TypeDataBase getTypeDataBase() { | |
189 return db; | |
190 } | |
191 | |
192 /** Indicates whether the target process is suspended | |
193 completely. Equivalent to getProcessControl().isSuspended(). */ | |
194 public synchronized boolean isSuspended() throws DebuggerException { | |
195 return getProcessControl().isSuspended(); | |
196 } | |
197 | |
198 /** Suspends the target process completely. Equivalent to | |
199 getProcessControl().suspend(). */ | |
200 public synchronized void suspend() throws DebuggerException { | |
201 getProcessControl().suspend(); | |
202 } | |
203 | |
204 /** Resumes the target process completely. Equivalent to | |
205 getProcessControl().suspend(). */ | |
206 public synchronized void resume() throws DebuggerException { | |
207 getProcessControl().resume(); | |
208 } | |
209 | |
210 /** Indicates whether we are attached to a Java HotSpot virtual | |
211 machine */ | |
212 public synchronized boolean isJavaMode() { | |
213 return javaMode; | |
214 } | |
215 | |
216 /** Temporarily disables interaction with the target process via | |
217 JVMDI. This is done while the target process is stopped at a C | |
218 breakpoint. Can be called even if the JVMDI agent has not been | |
219 initialized. */ | |
220 public synchronized void disableJavaInteraction() { | |
221 javaInteractionDisabled = true; | |
222 } | |
223 | |
224 /** Re-enables interaction with the target process via JVMDI. This | |
225 is done while the target process is continued past a C | |
226 braekpoint. Can be called even if the JVMDI agent has not been | |
227 initialized. */ | |
228 public synchronized void enableJavaInteraction() { | |
229 javaInteractionDisabled = false; | |
230 } | |
231 | |
232 /** Indicates whether Java interaction has been disabled */ | |
233 public synchronized boolean isJavaInteractionDisabled() { | |
234 return javaInteractionDisabled; | |
235 } | |
236 | |
237 /** Indicates whether we can talk to the Serviceability Agent's | |
238 JVMDI module to be able to set breakpoints */ | |
239 public synchronized boolean canInteractWithJava() { | |
240 return (jvmdi != null) && !javaInteractionDisabled; | |
241 } | |
242 | |
243 /** Suspends all Java threads in the target process. Can only be | |
244 called if we are attached to a HotSpot JVM and can connect to | |
245 the SA's JVMDI module. Must not be called when the target | |
246 process has been suspended with suspend(). */ | |
247 public synchronized void suspendJava() throws DebuggerException { | |
248 if (!canInteractWithJava()) { | |
249 throw new DebuggerException("Could not connect to SA's JVMDI module"); | |
250 } | |
251 if (jvmdi.isSuspended()) { | |
252 throw new DebuggerException("Target process already suspended via JVMDI"); | |
253 } | |
254 jvmdi.suspend(); | |
255 } | |
256 | |
257 /** Resumes all Java threads in the target process. Can only be | |
258 called if we are attached to a HotSpot JVM and can connect to | |
259 the SA's JVMDI module. Must not be called when the target | |
260 process has been suspended with suspend(). */ | |
261 public synchronized void resumeJava() throws DebuggerException { | |
262 if (!canInteractWithJava()) { | |
263 throw new DebuggerException("Could not connect to SA's JVMDI module"); | |
264 } | |
265 if (!jvmdi.isSuspended()) { | |
266 throw new DebuggerException("Target process already resumed via JVMDI"); | |
267 } | |
268 jvmdi.resume(); | |
269 } | |
270 | |
271 /** Indicates whether the target process has been suspended at the | |
272 Java language level via the SA's JVMDI module */ | |
273 public synchronized boolean isJavaSuspended() throws DebuggerException { | |
274 return jvmdi.isSuspended(); | |
275 } | |
276 | |
277 /** Toggle a Java breakpoint at the given location. */ | |
278 public synchronized ServiceabilityAgentJVMDIModule.BreakpointToggleResult | |
279 toggleJavaBreakpoint(String srcFileName, | |
280 String pkgName, | |
281 int lineNo) { | |
282 if (!canInteractWithJava()) { | |
283 throw new DebuggerException("Could not connect to SA's JVMDI module; can not toggle Java breakpoints"); | |
284 } | |
285 return jvmdi.toggleBreakpoint(srcFileName, pkgName, lineNo); | |
286 } | |
287 | |
288 /** Access to JVMDI module's eventPending */ | |
289 public synchronized boolean javaEventPending() throws DebuggerException { | |
290 if (!canInteractWithJava()) { | |
291 throw new DebuggerException("Could not connect to SA's JVMDI module; can not poll for Java debug events"); | |
292 } | |
293 return jvmdi.eventPending(); | |
294 } | |
295 | |
296 /** Access to JVMDI module's eventPoll */ | |
297 public synchronized Event javaEventPoll() throws DebuggerException { | |
298 if (!canInteractWithJava()) { | |
299 throw new DebuggerException("Could not connect to SA's JVMDI module; can not poll for Java debug events"); | |
300 } | |
301 return jvmdi.eventPoll(); | |
302 } | |
303 | |
304 /** Access to JVMDI module's eventContinue */ | |
305 public synchronized void javaEventContinue() throws DebuggerException { | |
306 if (!canInteractWithJava()) { | |
307 throw new DebuggerException("Could not connect to SA's JVMDI module; can not continue past Java debug events"); | |
308 } | |
309 jvmdi.eventContinue(); | |
310 } | |
311 | |
312 | |
313 // FIXME: add other accessors. For example, suspension and | |
314 // resumption should be done through this interface, as well as | |
315 // interaction with the live Java process such as breakpoint setting. | |
316 // Probably should not expose the ServiceabilityAgentJVMDIModule | |
317 // from this interface. | |
318 | |
319 //-------------------------------------------------------------------------------- | |
320 // Client-side operations | |
321 // | |
322 | |
323 /** This attaches to a process running on the local machine. */ | |
324 public synchronized void attach(int processID) | |
325 throws DebuggerException { | |
326 if (debugger != null) { | |
327 throw new DebuggerException("Already attached"); | |
328 } | |
329 pid = processID; | |
330 startupMode = PROCESS_MODE; | |
331 isServer = false; | |
332 go(); | |
333 } | |
334 | |
335 /** This opens a core file on the local machine */ | |
336 public synchronized void attach(String executableName, String coreFileName) | |
337 throws DebuggerException { | |
338 if (debugger != null) { | |
339 throw new DebuggerException("Already attached"); | |
340 } | |
341 if ((executableName == null) || (coreFileName == null)) { | |
342 throw new DebuggerException("Both the core file name and executable name must be specified"); | |
343 } | |
344 this.executableName = executableName; | |
345 this.coreFileName = coreFileName; | |
346 startupMode = CORE_FILE_MODE; | |
347 isServer = false; | |
348 go(); | |
349 } | |
350 | |
351 /** This attaches to a "debug server" on a remote machine; this | |
352 remote server has already attached to a process or opened a | |
353 core file and is waiting for RMI calls on the Debugger object to | |
354 come in. */ | |
355 public synchronized void attach(String remoteServerID) | |
356 throws DebuggerException { | |
357 if (debugger != null) { | |
358 throw new DebuggerException("Already attached to a process"); | |
359 } | |
360 if (remoteServerID == null) { | |
361 throw new DebuggerException("Debug server id must be specified"); | |
362 } | |
363 | |
364 debugServerID = remoteServerID; | |
365 startupMode = REMOTE_MODE; | |
366 isServer = false; | |
367 go(); | |
368 } | |
369 | |
370 /** This should only be called by the user on the client machine, | |
371 not the server machine */ | |
372 public synchronized boolean detach() throws DebuggerException { | |
373 if (isServer) { | |
374 throw new DebuggerException("Should not call detach() for server configuration"); | |
375 } | |
376 return detachInternal(); | |
377 } | |
378 | |
379 //-------------------------------------------------------------------------------- | |
380 // Server-side operations | |
381 // | |
382 | |
383 /** This attaches to a process running on the local machine and | |
384 starts a debug server, allowing remote machines to connect and | |
385 examine this process. uniqueID is used to uniquely identify the | |
386 debuggee */ | |
387 public synchronized void startServer(int processID, String uniqueID) | |
388 throws DebuggerException { | |
389 if (debugger != null) { | |
390 throw new DebuggerException("Already attached"); | |
391 } | |
392 pid = processID; | |
393 startupMode = PROCESS_MODE; | |
394 isServer = true; | |
395 serverID = uniqueID; | |
396 go(); | |
397 } | |
398 | |
399 /** This attaches to a process running on the local machine and | |
400 starts a debug server, allowing remote machines to connect and | |
401 examine this process. */ | |
402 public synchronized void startServer(int processID) | |
403 throws DebuggerException { | |
404 startServer(processID, null); | |
405 } | |
406 | |
407 /** This opens a core file on the local machine and starts a debug | |
408 server, allowing remote machines to connect and examine this | |
409 core file. uniqueID is used to uniquely identify the | |
410 debuggee */ | |
411 public synchronized void startServer(String executableName, String coreFileName, | |
412 String uniqueID) | |
413 throws DebuggerException { | |
414 if (debugger != null) { | |
415 throw new DebuggerException("Already attached"); | |
416 } | |
417 if ((executableName == null) || (coreFileName == null)) { | |
418 throw new DebuggerException("Both the core file name and Java executable name must be specified"); | |
419 } | |
420 this.executableName = executableName; | |
421 this.coreFileName = coreFileName; | |
422 startupMode = CORE_FILE_MODE; | |
423 isServer = true; | |
424 serverID = uniqueID; | |
425 go(); | |
426 } | |
427 | |
428 /** This opens a core file on the local machine and starts a debug | |
429 server, allowing remote machines to connect and examine this | |
430 core file.*/ | |
431 public synchronized void startServer(String executableName, String coreFileName) | |
432 throws DebuggerException { | |
433 startServer(executableName, coreFileName, null); | |
434 } | |
435 | |
436 /** This may only be called on the server side after startServer() | |
437 has been called */ | |
438 public synchronized boolean shutdownServer() throws DebuggerException { | |
439 if (!isServer) { | |
440 throw new DebuggerException("Should not call shutdownServer() for client configuration"); | |
441 } | |
442 return detachInternal(); | |
443 } | |
444 | |
445 | |
446 //-------------------------------------------------------------------------------- | |
447 // Internals only below this point | |
448 // | |
449 | |
450 private boolean detachInternal() { | |
451 if (debugger == null) { | |
452 return false; | |
453 } | |
454 if (canInteractWithJava()) { | |
455 jvmdi.detach(); | |
456 jvmdi = null; | |
457 } | |
458 boolean retval = true; | |
459 if (!isServer) { | |
460 VM.shutdown(); | |
461 } | |
462 // We must not call detach() if we are a client and are connected | |
463 // to a remote debugger | |
464 Debugger dbg = null; | |
465 DebuggerException ex = null; | |
466 if (isServer) { | |
467 try { | |
468 RMIHelper.unbind(serverID); | |
469 } | |
470 catch (DebuggerException de) { | |
471 ex = de; | |
472 } | |
473 dbg = debugger; | |
474 } else { | |
475 if (startupMode != REMOTE_MODE) { | |
476 dbg = debugger; | |
477 } | |
478 } | |
479 if (dbg != null) { | |
480 retval = dbg.detach(); | |
481 } | |
482 | |
483 debugger = null; | |
484 machDesc = null; | |
485 db = null; | |
486 if (ex != null) { | |
487 throw(ex); | |
488 } | |
489 return retval; | |
490 } | |
491 | |
492 private void go() { | |
493 setupDebugger(); | |
494 javaMode = setupVM(); | |
495 } | |
496 | |
497 private void setupDebugger() { | |
498 if (startupMode != REMOTE_MODE) { | |
499 // | |
500 // Local mode (client attaching to local process or setting up | |
501 // server, but not client attaching to server) | |
502 // | |
503 | |
504 try { | |
505 os = PlatformInfo.getOS(); | |
506 cpu = PlatformInfo.getCPU(); | |
507 } | |
508 catch (UnsupportedPlatformException e) { | |
509 throw new DebuggerException(e); | |
510 } | |
511 fileSep = System.getProperty("file.separator"); | |
512 | |
513 if (os.equals("solaris")) { | |
514 setupDebuggerSolaris(); | |
515 } else if (os.equals("win32")) { | |
516 setupDebuggerWin32(); | |
517 } else if (os.equals("linux")) { | |
518 setupDebuggerLinux(); | |
519 } else { | |
520 // Add support for more operating systems here | |
521 throw new DebuggerException("Operating system " + os + " not yet supported"); | |
522 } | |
523 if (isServer) { | |
524 RemoteDebuggerServer remote = null; | |
525 try { | |
526 remote = new RemoteDebuggerServer(debugger); | |
527 } | |
528 catch (RemoteException rem) { | |
529 throw new DebuggerException(rem); | |
530 } | |
531 RMIHelper.rebind(serverID, remote); | |
532 } | |
533 } else { | |
534 // | |
535 // Remote mode (client attaching to server) | |
536 // | |
537 | |
538 // Create and install a security manager | |
539 | |
540 // FIXME: currently commented out because we were having | |
541 // security problems since we're "in the sun.* hierarchy" here. | |
542 // Perhaps a permissive policy file would work around this. In | |
543 // the long run, will probably have to move into com.sun.*. | |
544 | |
545 // if (System.getSecurityManager() == null) { | |
546 // System.setSecurityManager(new RMISecurityManager()); | |
547 // } | |
548 | |
549 connectRemoteDebugger(); | |
550 } | |
551 } | |
552 | |
553 private boolean setupVM() { | |
554 // We need to instantiate a HotSpotTypeDataBase on both the client | |
555 // and server machine. On the server it is only currently used to | |
556 // configure the Java primitive type sizes (which we should | |
557 // consider making constant). On the client it is used to | |
558 // configure the VM. | |
559 | |
560 try { | |
561 if (os.equals("solaris")) { | |
562 db = new HotSpotTypeDataBase(machDesc, new HotSpotSolarisVtblAccess(debugger, jvmLibNames), | |
563 debugger, jvmLibNames); | |
564 } else if (os.equals("win32")) { | |
565 db = new HotSpotTypeDataBase(machDesc, new Win32VtblAccess(debugger, jvmLibNames), | |
566 debugger, jvmLibNames); | |
567 } else if (os.equals("linux")) { | |
568 db = new HotSpotTypeDataBase(machDesc, new LinuxVtblAccess(debugger, jvmLibNames), | |
569 debugger, jvmLibNames); | |
570 } else { | |
571 throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess implemented yet)"); | |
572 } | |
573 } | |
574 catch (NoSuchSymbolException e) { | |
575 e.printStackTrace(); | |
576 return false; | |
577 } | |
578 | |
579 if (startupMode != REMOTE_MODE) { | |
580 // Configure the debugger with the primitive type sizes just obtained from the VM | |
581 debugger.configureJavaPrimitiveTypeSizes(db.getJBooleanType().getSize(), | |
582 db.getJByteType().getSize(), | |
583 db.getJCharType().getSize(), | |
584 db.getJDoubleType().getSize(), | |
585 db.getJFloatType().getSize(), | |
586 db.getJIntType().getSize(), | |
587 db.getJLongType().getSize(), | |
588 db.getJShortType().getSize()); | |
589 } | |
590 | |
591 if (!isServer) { | |
592 // Do not initialize the VM on the server (unnecessary, since it's | |
593 // instantiated on the client) | |
594 VM.initialize(db, debugger); | |
595 } | |
596 | |
597 try { | |
598 jvmdi = new ServiceabilityAgentJVMDIModule(debugger, saLibNames); | |
599 if (jvmdi.canAttach()) { | |
600 jvmdi.attach(); | |
601 jvmdi.setCommandTimeout(6000); | |
602 debugPrintln("Attached to Serviceability Agent's JVMDI module."); | |
603 // Jog VM to suspended point with JVMDI module | |
604 resume(); | |
605 suspendJava(); | |
606 suspend(); | |
607 debugPrintln("Suspended all Java threads."); | |
608 } else { | |
609 debugPrintln("Could not locate SA's JVMDI module; skipping attachment"); | |
610 jvmdi = null; | |
611 } | |
612 } catch (Exception e) { | |
613 e.printStackTrace(); | |
614 jvmdi = null; | |
615 } | |
616 | |
617 return true; | |
618 } | |
619 | |
620 //-------------------------------------------------------------------------------- | |
621 // OS-specific debugger setup/connect routines | |
622 // | |
623 | |
624 // | |
625 // Solaris | |
626 // | |
627 | |
628 private void setupDebuggerSolaris() { | |
629 setupJVMLibNamesSolaris(); | |
630 String prop = System.getProperty("sun.jvm.hotspot.debugger.useProcDebugger"); | |
631 if (prop != null && !prop.equals("false")) { | |
632 ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true); | |
633 debugger = dbg; | |
634 attachDebugger(); | |
635 | |
636 // Set up CPU-dependent stuff | |
637 if (cpu.equals("x86")) { | |
638 machDesc = new MachineDescriptionIntelX86(); | |
639 } else if (cpu.equals("sparc")) { | |
640 int addressSize = dbg.getRemoteProcessAddressSize(); | |
641 if (addressSize == -1) { | |
642 throw new DebuggerException("Error occurred while trying to determine the remote process's address size"); | |
643 } | |
644 | |
645 if (addressSize == 32) { | |
646 machDesc = new MachineDescriptionSPARC32Bit(); | |
647 } else if (addressSize == 64) { | |
648 machDesc = new MachineDescriptionSPARC64Bit(); | |
649 } else { | |
650 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); | |
651 } | |
652 } else if (cpu.equals("amd64")) { | |
653 machDesc = new MachineDescriptionAMD64(); | |
654 } else { | |
655 throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64"); | |
656 } | |
657 | |
658 dbg.setMachineDescription(machDesc); | |
659 return; | |
660 } else { | |
661 String dbxPathName; | |
662 String dbxPathPrefix; | |
663 String dbxSvcAgentDSOPathName; | |
664 String dbxSvcAgentDSOPathPrefix; | |
665 String[] dbxSvcAgentDSOPathNames = null; | |
666 | |
667 // use path names/prefixes specified on command | |
668 dbxPathName = System.getProperty("dbxPathName"); | |
669 if (dbxPathName == null) { | |
670 dbxPathPrefix = System.getProperty("dbxPathPrefix"); | |
671 if (dbxPathPrefix == null) { | |
672 dbxPathPrefix = defaultDbxPathPrefix; | |
673 } | |
674 dbxPathName = dbxPathPrefix + fileSep + os + fileSep + cpu + fileSep + "bin" + fileSep + "dbx"; | |
675 } | |
676 | |
677 dbxSvcAgentDSOPathName = System.getProperty("dbxSvcAgentDSOPathName"); | |
678 if (dbxSvcAgentDSOPathName != null) { | |
679 dbxSvcAgentDSOPathNames = new String[] { dbxSvcAgentDSOPathName } ; | |
680 } else { | |
681 dbxSvcAgentDSOPathPrefix = System.getProperty("dbxSvcAgentDSOPathPrefix"); | |
682 if (dbxSvcAgentDSOPathPrefix == null) { | |
683 dbxSvcAgentDSOPathPrefix = defaultDbxSvcAgentDSOPathPrefix; | |
684 } | |
685 if (cpu.equals("sparc")) { | |
686 dbxSvcAgentDSOPathNames = new String[] { | |
687 // FIXME: bad hack for SPARC v9. This is necessary because | |
688 // there are two dbx executables on SPARC, one for v8 and one | |
689 // for v9, and it isn't obvious how to tell the two apart | |
690 // using the dbx command line. See | |
691 // DbxDebuggerLocal.importDbxModule(). | |
692 dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + "v9" + fileSep + "lib" + fileSep + "libsvc_agent_dbx.so", | |
693 dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + fileSep + "lib" + fileSep + "libsvc_agent_dbx.so", | |
694 }; | |
695 } else { | |
696 dbxSvcAgentDSOPathNames = new String[] { | |
697 dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + fileSep + "lib" + fileSep + "libsvc_agent_dbx.so" | |
698 }; | |
699 } | |
700 } | |
701 // Note we do not use a cache for the local debugger in server | |
702 // mode; it's taken care of on the client side | |
703 DbxDebuggerLocal dbg = new DbxDebuggerLocal(null, dbxPathName, dbxSvcAgentDSOPathNames, !isServer); | |
704 debugger = dbg; | |
705 | |
706 attachDebugger(); | |
707 | |
708 // Set up CPU-dependent stuff | |
709 if (cpu.equals("x86")) { | |
710 machDesc = new MachineDescriptionIntelX86(); | |
711 } else if (cpu.equals("sparc")) { | |
712 int addressSize = dbg.getRemoteProcessAddressSize(); | |
713 if (addressSize == -1) { | |
714 throw new DebuggerException("Error occurred while trying to determine the remote process's address size. It's possible that the Serviceability Agent's dbx module failed to initialize. Examine the standard output and standard error streams from the dbx process for more information."); | |
715 } | |
716 | |
717 if (addressSize == 32) { | |
718 machDesc = new MachineDescriptionSPARC32Bit(); | |
719 } else if (addressSize == 64) { | |
720 machDesc = new MachineDescriptionSPARC64Bit(); | |
721 } else { | |
722 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); | |
723 } | |
724 } | |
725 | |
726 dbg.setMachineDescription(machDesc); | |
727 } | |
728 } | |
729 | |
730 private void connectRemoteDebugger() throws DebuggerException { | |
731 RemoteDebugger remote = | |
732 (RemoteDebugger) RMIHelper.lookup(debugServerID); | |
733 debugger = new RemoteDebuggerClient(remote); | |
734 machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription(); | |
735 os = debugger.getOS(); | |
736 if (os.equals("solaris")) { | |
737 setupJVMLibNamesSolaris(); | |
738 } else if (os.equals("win32")) { | |
739 setupJVMLibNamesWin32(); | |
740 } else if (os.equals("linux")) { | |
741 setupJVMLibNamesLinux(); | |
742 } else { | |
743 throw new RuntimeException("Unknown OS type"); | |
744 } | |
745 | |
746 cpu = debugger.getCPU(); | |
747 } | |
748 | |
749 private void setupJVMLibNamesSolaris() { | |
750 jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" }; | |
751 saLibNames = new String[] { "libsa.so", "libsa_g.so" }; | |
752 } | |
753 | |
754 // | |
755 // Win32 | |
756 // | |
757 | |
758 private void setupDebuggerWin32() { | |
759 setupJVMLibNamesWin32(); | |
760 | |
761 if (cpu.equals("x86")) { | |
762 machDesc = new MachineDescriptionIntelX86(); | |
763 } else if (cpu.equals("amd64")) { | |
764 machDesc = new MachineDescriptionAMD64(); | |
765 } else if (cpu.equals("ia64")) { | |
766 machDesc = new MachineDescriptionIA64(); | |
767 } else { | |
768 throw new DebuggerException("Win32 supported under x86, amd64 and ia64 only"); | |
769 } | |
770 | |
771 // Note we do not use a cache for the local debugger in server | |
772 // mode; it will be taken care of on the client side (once remote | |
773 // debugging is implemented). | |
774 | |
775 if (System.getProperty("sun.jvm.hotspot.debugger.useWindbgDebugger") != null) { | |
776 debugger = new WindbgDebuggerLocal(machDesc, !isServer); | |
777 } else { | |
778 debugger = new Win32DebuggerLocal(machDesc, !isServer); | |
779 } | |
780 | |
781 attachDebugger(); | |
782 } | |
783 | |
784 private void setupJVMLibNamesWin32() { | |
785 jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" }; | |
786 saLibNames = new String[] { "sa.dll", "sa_g.dll" }; | |
787 } | |
788 | |
789 // | |
790 // Linux | |
791 // | |
792 | |
793 private void setupDebuggerLinux() { | |
794 setupJVMLibNamesLinux(); | |
795 | |
796 if (cpu.equals("x86")) { | |
797 machDesc = new MachineDescriptionIntelX86(); | |
798 } else if (cpu.equals("ia64")) { | |
799 machDesc = new MachineDescriptionIA64(); | |
800 } else if (cpu.equals("amd64")) { | |
801 machDesc = new MachineDescriptionAMD64(); | |
802 } else if (cpu.equals("sparc")) { | |
803 if (LinuxDebuggerLocal.getAddressSize()==8) { | |
804 machDesc = new MachineDescriptionSPARC64Bit(); | |
805 } else { | |
806 machDesc = new MachineDescriptionSPARC32Bit(); | |
807 } | |
808 } else { | |
809 throw new DebuggerException("Linux only supported on x86/ia64/amd64/sparc/sparc64"); | |
810 } | |
811 | |
812 // Note we do not use a cache for the local debugger in server | |
813 // mode; it will be taken care of on the client side (once remote | |
814 // debugging is implemented). | |
815 | |
816 debugger = new LinuxDebuggerLocal(machDesc, !isServer); | |
817 attachDebugger(); | |
818 } | |
819 | |
820 private void setupJVMLibNamesLinux() { | |
821 // same as solaris | |
822 setupJVMLibNamesSolaris(); | |
823 } | |
824 | |
825 /** Convenience routine which should be called by per-platform | |
826 debugger setup. Should not be called when startupMode is | |
827 REMOTE_MODE. */ | |
828 private void attachDebugger() { | |
829 if (startupMode == PROCESS_MODE) { | |
830 debugger.attach(pid); | |
831 } else if (startupMode == CORE_FILE_MODE) { | |
832 debugger.attach(executableName, coreFileName); | |
833 } else { | |
834 throw new DebuggerException("Should not call attach() for startupMode == " + startupMode); | |
835 } | |
836 } | |
837 } |