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.proc.*;
  33 import sun.jvm.hotspot.debugger.cdbg.*;
  34 import sun.jvm.hotspot.debugger.win32.*;
  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 {
 515                 // Add support for more operating systems here
 516                 throw new DebuggerException("Operating system " + os + " not yet supported");
 517             }
 518             if (isServer) {
 519                 RemoteDebuggerServer remote = null;
 520                 try {
 521                     remote = new RemoteDebuggerServer(debugger);
 522                 }
 523                 catch (RemoteException rem) {
 524                     throw new DebuggerException(rem);
 525                 }
 526                 RMIHelper.rebind(serverID, remote);
 527             }
 528         } else {
 529             //
 530             // Remote mode (client attaching to server)
 531             //
 532 
 533             // Create and install a security manager
 534 
 535             // FIXME: currently commented out because we were having
 536             // security problems since we're "in the sun.* hierarchy" here.
 537             // Perhaps a permissive policy file would work around this. In
 538             // the long run, will probably have to move into com.sun.*.
 539 
 540             //    if (System.getSecurityManager() == null) {
 541             //      System.setSecurityManager(new RMISecurityManager());
 542             //    }
 543 
 544             connectRemoteDebugger();
 545         }
 546     }
 547 
 548     private boolean setupVM() {
 549         // We need to instantiate a HotSpotTypeDataBase on both the client
 550         // and server machine. On the server it is only currently used to
 551         // configure the Java primitive type sizes (which we should
 552         // consider making constant). On the client it is used to
 553         // configure the VM.
 554 
 555         try {
 556             if (os.equals("solaris")) {
 557                 db = new HotSpotTypeDataBase(machDesc, new HotSpotSolarisVtblAccess(debugger, jvmLibNames),
 558                 debugger, jvmLibNames);
 559             } else if (os.equals("win32")) {
 560                 db = new HotSpotTypeDataBase(machDesc, new Win32VtblAccess(debugger, jvmLibNames),
 561                 debugger, jvmLibNames);
 562             } else if (os.equals("linux")) {
 563                 db = new HotSpotTypeDataBase(machDesc, new LinuxVtblAccess(debugger, jvmLibNames),
 564                 debugger, jvmLibNames);
 565             } else {
 566                 throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess implemented yet)");
 567             }
 568         }
 569         catch (NoSuchSymbolException e) {
 570             e.printStackTrace();
 571             return false;
 572         }
 573 
 574         if (startupMode != REMOTE_MODE) {
 575             // Configure the debugger with the primitive type sizes just obtained from the VM
 576             debugger.configureJavaPrimitiveTypeSizes(db.getJBooleanType().getSize(),
 577             db.getJByteType().getSize(),
 578             db.getJCharType().getSize(),
 579             db.getJDoubleType().getSize(),
 580             db.getJFloatType().getSize(),
 581             db.getJIntType().getSize(),
 582             db.getJLongType().getSize(),
 583             db.getJShortType().getSize());
 584         }
 585 
 586         if (!isServer) {
 587             // Do not initialize the VM on the server (unnecessary, since it's
 588             // instantiated on the client)
 589             VM.initialize(db, debugger);
 590         }
 591 
 592         try {
 593             jvmdi = new ServiceabilityAgentJVMDIModule(debugger, saLibNames);
 594             if (jvmdi.canAttach()) {
 595                 jvmdi.attach();
 596                 jvmdi.setCommandTimeout(6000);
 597                 debugPrintln("Attached to Serviceability Agent's JVMDI module.");
 598                 // Jog VM to suspended point with JVMDI module
 599                 resume();
 600                 suspendJava();
 601                 suspend();
 602                 debugPrintln("Suspended all Java threads.");
 603             } else {
 604                 debugPrintln("Could not locate SA's JVMDI module; skipping attachment");
 605                 jvmdi = null;
 606             }
 607         } catch (Exception e) {
 608             e.printStackTrace();
 609             jvmdi = null;
 610         }
 611 
 612         return true;
 613     }
 614 
 615     //--------------------------------------------------------------------------------
 616     // OS-specific debugger setup/connect routines
 617     //
 618 
 619     //
 620     // Solaris
 621     //
 622 
 623     private void setupDebuggerSolaris() {
 624         setupJVMLibNamesSolaris();
 625         ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true);
 626         debugger = dbg;
 627         attachDebugger();
 628 
 629         // Set up CPU-dependent stuff
 630         if (cpu.equals("x86")) {
 631             machDesc = new MachineDescriptionIntelX86();
 632         } else if (cpu.equals("sparc")) {
 633             int addressSize = dbg.getRemoteProcessAddressSize();
 634             if (addressSize == -1) {
 635                 throw new DebuggerException("Error occurred while trying to determine the remote process's address size");
 636             }
 637 
 638             if (addressSize == 32) {
 639                 machDesc = new MachineDescriptionSPARC32Bit();
 640             } else if (addressSize == 64) {
 641                 machDesc = new MachineDescriptionSPARC64Bit();
 642             } else {
 643                 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC");
 644             }
 645         } else if (cpu.equals("amd64")) {
 646             machDesc = new MachineDescriptionAMD64();
 647         } else {
 648             throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64");
 649         }
 650 
 651         dbg.setMachineDescription(machDesc);
 652     }
 653 
 654     private void connectRemoteDebugger() throws DebuggerException {
 655         RemoteDebugger remote =
 656         (RemoteDebugger) RMIHelper.lookup(debugServerID);
 657         debugger = new RemoteDebuggerClient(remote);
 658         machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription();
 659         os = debugger.getOS();
 660         if (os.equals("solaris")) {
 661             setupJVMLibNamesSolaris();
 662         } else if (os.equals("win32")) {
 663             setupJVMLibNamesWin32();
 664         } else if (os.equals("linux")) {
 665             setupJVMLibNamesLinux();
 666         } else {
 667             throw new RuntimeException("Unknown OS type");
 668         }
 669 
 670         cpu = debugger.getCPU();
 671     }
 672 
 673     private void setupJVMLibNamesSolaris() {
 674         jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" };
 675         saLibNames = new String[] { "libsa.so", "libsa_g.so" };
 676     }
 677 
 678     //
 679     // Win32
 680     //
 681 
 682     private void setupDebuggerWin32() {
 683         setupJVMLibNamesWin32();
 684 
 685         if (cpu.equals("x86")) {
 686             machDesc = new MachineDescriptionIntelX86();
 687         } else if (cpu.equals("amd64")) {
 688             machDesc = new MachineDescriptionAMD64();
 689         } else if (cpu.equals("ia64")) {
 690             machDesc = new MachineDescriptionIA64();
 691         } else {
 692             throw new DebuggerException("Win32 supported under x86, amd64 and ia64 only");
 693         }
 694 
 695         // Note we do not use a cache for the local debugger in server
 696         // mode; it will be taken care of on the client side (once remote
 697         // debugging is implemented).
 698 
 699         if (System.getProperty("sun.jvm.hotspot.debugger.useWindbgDebugger") != null) {
 700             debugger = new WindbgDebuggerLocal(machDesc, !isServer);
 701         } else {
 702             debugger = new Win32DebuggerLocal(machDesc, !isServer);
 703         }
 704 
 705         attachDebugger();
 706     }
 707 
 708     private void setupJVMLibNamesWin32() {
 709         jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" };
 710         saLibNames = new String[] { "sa.dll", "sa_g.dll" };
 711     }
 712 
 713     //
 714     // Linux
 715     //
 716 
 717     private void setupDebuggerLinux() {
 718         setupJVMLibNamesLinux();
 719 
 720         if (cpu.equals("x86")) {
 721             machDesc = new MachineDescriptionIntelX86();
 722         } else if (cpu.equals("ia64")) {
 723             machDesc = new MachineDescriptionIA64();
 724         } else if (cpu.equals("amd64")) {
 725             machDesc = new MachineDescriptionAMD64();
 726         } else if (cpu.equals("sparc")) {
 727             if (LinuxDebuggerLocal.getAddressSize()==8) {
 728                machDesc = new MachineDescriptionSPARC64Bit();
 729             } else {
 730                machDesc = new MachineDescriptionSPARC32Bit();
 731             }
 732         } else {
 733             throw new DebuggerException("Linux only supported on x86/ia64/amd64/sparc/sparc64");
 734         }
 735 
 736         // Note we do not use a cache for the local debugger in server
 737         // mode; it will be taken care of on the client side (once remote
 738         // debugging is implemented).
 739 
 740         debugger = new LinuxDebuggerLocal(machDesc, !isServer);
 741         attachDebugger();
 742     }
 743 
 744     private void setupJVMLibNamesLinux() {
 745         // same as solaris
 746         setupJVMLibNamesSolaris();
 747     }
 748 
 749     /** Convenience routine which should be called by per-platform
 750       debugger setup. Should not be called when startupMode is
 751       REMOTE_MODE. */
 752     private void attachDebugger() {
 753         if (startupMode == PROCESS_MODE) {
 754             debugger.attach(pid);
 755         } else if (startupMode == CORE_FILE_MODE) {
 756             debugger.attach(executableName, coreFileName);
 757         } else {
 758             throw new DebuggerException("Should not call attach() for startupMode == " + startupMode);
 759         }
 760     }
 761 }