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