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