comparison agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2002-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 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 }