1 /*
   2  * Copyright (c) 2000, 2020, 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;
  26 
  27 import java.rmi.RemoteException;
  28 import java.lang.reflect.Constructor;
  29 import java.lang.reflect.InvocationTargetException;
  30 
  31 import sun.jvm.hotspot.debugger.Debugger;
  32 import sun.jvm.hotspot.debugger.DebuggerException;
  33 import sun.jvm.hotspot.debugger.JVMDebugger;
  34 import sun.jvm.hotspot.debugger.MachineDescription;
  35 import sun.jvm.hotspot.debugger.MachineDescriptionAMD64;
  36 import sun.jvm.hotspot.debugger.MachineDescriptionPPC64;
  37 import sun.jvm.hotspot.debugger.MachineDescriptionAArch64;
  38 import sun.jvm.hotspot.debugger.MachineDescriptionIntelX86;
  39 import sun.jvm.hotspot.debugger.MachineDescriptionSPARC32Bit;
  40 import sun.jvm.hotspot.debugger.MachineDescriptionSPARC64Bit;
  41 import sun.jvm.hotspot.debugger.NoSuchSymbolException;
  42 import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal;
  43 import sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal;
  44 import sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal;
  45 import sun.jvm.hotspot.debugger.remote.RemoteDebugger;
  46 import sun.jvm.hotspot.debugger.remote.RemoteDebuggerClient;
  47 import sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer;
  48 import sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal;
  49 import sun.jvm.hotspot.runtime.VM;
  50 import sun.jvm.hotspot.types.TypeDataBase;
  51 import sun.jvm.hotspot.utilities.PlatformInfo;
  52 import sun.jvm.hotspot.utilities.UnsupportedPlatformException;
  53 
  54 /** <P> This class wraps much of the basic functionality and is the
  55  * highest-level factory for VM data structures. It makes it simple
  56  * to start up the debugging system. </P>
  57  *
  58  * <P> FIXME: especially with the addition of remote debugging, this
  59  * has turned into a mess; needs rethinking. </P>
  60  */
  61 
  62 public class HotSpotAgent {
  63     private JVMDebugger debugger;
  64     private MachineDescription machDesc;
  65     private TypeDataBase db;
  66 
  67     private String os;
  68     private String cpu;
  69 
  70     // The system can work in several ways:
  71     //  - Attaching to local process
  72     //  - Attaching to local core file
  73     //  - Connecting to remote debug server
  74     //  - Starting debug server for process
  75     //  - Starting debug server for core file
  76 
  77     // These are options for the "client" side of things
  78     private static final int PROCESS_MODE   = 0;
  79     private static final int CORE_FILE_MODE = 1;
  80     private static final int REMOTE_MODE    = 2;
  81     private int startupMode;
  82 
  83     // This indicates whether we are really starting a server or not
  84     private boolean isServer;
  85 
  86     // All possible required information for connecting
  87     private int pid;
  88     private String javaExecutableName;
  89     private String coreFileName;
  90     private String debugServerID;
  91     private int rmiPort;
  92 
  93     // All needed information for server side
  94     private String serverID;
  95 
  96     private String[] jvmLibNames;
  97 
  98     static void showUsage() {
  99     }
 100 
 101     public HotSpotAgent() {
 102         // for non-server add shutdown hook to clean-up debugger in case
 103         // of forced exit. For remote server, shutdown hook is added by
 104         // DebugServer.
 105         Runtime.getRuntime().addShutdownHook(new java.lang.Thread(
 106         new Runnable() {
 107             public void run() {
 108                 synchronized (HotSpotAgent.this) {
 109                     if (!isServer) {
 110                         detach();
 111                     }
 112                 }
 113             }
 114         }));
 115     }
 116 
 117     //--------------------------------------------------------------------------------
 118     // Accessors (once the system is set up)
 119     //
 120 
 121     public synchronized Debugger getDebugger() {
 122         return debugger;
 123     }
 124 
 125     public synchronized TypeDataBase getTypeDataBase() {
 126         return db;
 127     }
 128 
 129     //--------------------------------------------------------------------------------
 130     // Client-side operations
 131     //
 132 
 133     /** This attaches to a process running on the local machine. */
 134     public synchronized void attach(int processID)
 135     throws DebuggerException {
 136         if (debugger != null) {
 137             throw new DebuggerException("Already attached");
 138         }
 139         pid = processID;
 140         startupMode = PROCESS_MODE;
 141         isServer = false;
 142         go();
 143     }
 144 
 145     /** This opens a core file on the local machine */
 146     public synchronized void attach(String javaExecutableName, String coreFileName)
 147     throws DebuggerException {
 148         if (debugger != null) {
 149             throw new DebuggerException("Already attached");
 150         }
 151         if ((javaExecutableName == null) || (coreFileName == null)) {
 152             throw new DebuggerException("Both the core file name and Java executable name must be specified");
 153         }
 154         this.javaExecutableName = javaExecutableName;
 155         this.coreFileName = coreFileName;
 156         startupMode = CORE_FILE_MODE;
 157         isServer = false;
 158         go();
 159     }
 160 
 161     /** This uses a JVMDebugger that is already attached to the core or process */
 162     public synchronized void attach(JVMDebugger d)
 163     throws DebuggerException {
 164         debugger = d;
 165         isServer = false;
 166         go();
 167     }
 168 
 169     /** This attaches to a "debug server" on a remote machine; this
 170       remote server has already attached to a process or opened a
 171       core file and is waiting for RMI calls on the Debugger object to
 172       come in. */
 173     public synchronized void attach(String remoteServerID)
 174     throws DebuggerException {
 175         if (debugger != null) {
 176             throw new DebuggerException("Already attached to a process");
 177         }
 178         if (remoteServerID == null) {
 179             throw new DebuggerException("Debug server id must be specified");
 180         }
 181 
 182         debugServerID = remoteServerID;
 183         startupMode = REMOTE_MODE;
 184         isServer = false;
 185         go();
 186     }
 187 
 188     /** This should only be called by the user on the client machine,
 189       not the server machine */
 190     public synchronized boolean detach() throws DebuggerException {
 191         if (isServer) {
 192             throw new DebuggerException("Should not call detach() for server configuration");
 193         }
 194         return detachInternal();
 195     }
 196 
 197     //--------------------------------------------------------------------------------
 198     // Server-side operations
 199     //
 200 
 201     /** This attaches to a process running on the local machine and
 202       starts a debug server, allowing remote machines to connect and
 203       examine this process. Uses specified name to uniquely identify a
 204       specific debuggee on the server. Allows to specify the port number
 205       to which the RMI connector is bound. If not specified a random
 206       available port is used. */
 207     public synchronized void startServer(int processID,
 208                                          String uniqueID,
 209                                          int rmiPort) {
 210         if (debugger != null) {
 211             throw new DebuggerException("Already attached");
 212         }
 213         pid = processID;
 214         startupMode = PROCESS_MODE;
 215         isServer = true;
 216         serverID = uniqueID;
 217         this.rmiPort = rmiPort;
 218         go();
 219     }
 220 
 221     /** This attaches to a process running on the local machine and
 222      starts a debug server, allowing remote machines to connect and
 223      examine this process. Uses specified name to uniquely identify a
 224      specific debuggee on the server */
 225     public synchronized void startServer(int processID, String uniqueID) {
 226         startServer(processID, uniqueID, 0);
 227     }
 228 
 229     /** This attaches to a process running on the local machine and
 230       starts a debug server, allowing remote machines to connect and
 231       examine this process. */
 232     public synchronized void startServer(int processID)
 233     throws DebuggerException {
 234         startServer(processID, null);
 235     }
 236 
 237     /** This opens a core file on the local machine and starts a debug
 238       server, allowing remote machines to connect and examine this
 239       core file. Uses supplied uniqueID to uniquely identify a specific
 240       debuggee. Allows to specify the port number to which the RMI connector
 241       is bound. If not specified a random available port is used.  */
 242     public synchronized void startServer(String javaExecutableName,
 243                                          String coreFileName,
 244                                          String uniqueID,
 245                                          int rmiPort) {
 246         if (debugger != null) {
 247             throw new DebuggerException("Already attached");
 248         }
 249         if ((javaExecutableName == null) || (coreFileName == null)) {
 250             throw new DebuggerException("Both the core file name and Java executable name must be specified");
 251         }
 252         this.javaExecutableName = javaExecutableName;
 253         this.coreFileName = coreFileName;
 254         startupMode = CORE_FILE_MODE;
 255         isServer = true;
 256         serverID = uniqueID;
 257         this.rmiPort = rmiPort;
 258         go();
 259     }
 260 
 261     /** This opens a core file on the local machine and starts a debug
 262      server, allowing remote machines to connect and examine this
 263      core file. Uses supplied uniqueID to uniquely identify a specific
 264      debugee */
 265     public synchronized void startServer(String javaExecutableName,
 266                                          String coreFileName,
 267                                          String uniqueID) {
 268         startServer(javaExecutableName, coreFileName, uniqueID, 0);
 269     }
 270 
 271     /** This opens a core file on the local machine and starts a debug
 272       server, allowing remote machines to connect and examine this
 273       core file. */
 274     public synchronized void startServer(String javaExecutableName, String coreFileName)
 275     throws DebuggerException {
 276         startServer(javaExecutableName, coreFileName, null);
 277     }
 278 
 279     /** This may only be called on the server side after startServer()
 280       has been called */
 281     public synchronized boolean shutdownServer() throws DebuggerException {
 282         if (!isServer) {
 283             throw new DebuggerException("Should not call shutdownServer() for client configuration");
 284         }
 285         return detachInternal();
 286     }
 287 
 288 
 289     //--------------------------------------------------------------------------------
 290     // Internals only below this point
 291     //
 292 
 293     private boolean detachInternal() {
 294         if (debugger == null) {
 295             return false;
 296         }
 297         boolean retval = true;
 298         if (!isServer) {
 299             VM.shutdown();
 300         }
 301         // We must not call detach() if we are a client and are connected
 302         // to a remote debugger
 303         Debugger dbg = null;
 304         DebuggerException ex = null;
 305         if (isServer) {
 306             try {
 307                 RMIHelper.unbind(serverID);
 308             }
 309             catch (DebuggerException de) {
 310                 ex = de;
 311             }
 312             dbg = debugger;
 313         } else {
 314             if (startupMode != REMOTE_MODE) {
 315                 dbg = debugger;
 316             }
 317         }
 318         if (dbg != null) {
 319             retval = dbg.detach();
 320         }
 321 
 322         debugger = null;
 323         machDesc = null;
 324         db = null;
 325         if (ex != null) {
 326             throw(ex);
 327         }
 328         return retval;
 329     }
 330 
 331     private void go() {
 332         setupDebugger();
 333         setupVM();
 334     }
 335 
 336     private void setupDebugger() {
 337         if (startupMode != REMOTE_MODE) {
 338             //
 339             // Local mode (client attaching to local process or setting up
 340             // server, but not client attaching to server)
 341             //
 342 
 343             // Handle existing or alternate JVMDebugger:
 344             // these will set os, cpu independently of our PlatformInfo implementation.
 345             String alternateDebugger = System.getProperty("sa.altDebugger");
 346             if (debugger != null) {
 347                 setupDebuggerExisting();
 348 
 349             } else if (alternateDebugger != null) {
 350                 setupDebuggerAlternate(alternateDebugger);
 351 
 352             } else {
 353                 // Otherwise, os, cpu are those of our current platform:
 354                 try {
 355                     os  = PlatformInfo.getOS();
 356                     cpu = PlatformInfo.getCPU();
 357                 } catch (UnsupportedPlatformException e) {
 358                    throw new DebuggerException(e);
 359                 }
 360                 if (os.equals("solaris")) {
 361                     setupDebuggerSolaris();
 362                 } else if (os.equals("win32")) {
 363                     setupDebuggerWin32();
 364                 } else if (os.equals("linux")) {
 365                     setupDebuggerLinux();
 366                 } else if (os.equals("bsd")) {
 367                     setupDebuggerBsd();
 368                 } else if (os.equals("darwin")) {
 369                     setupDebuggerDarwin();
 370                 } else {
 371                     // Add support for more operating systems here
 372                     throw new DebuggerException("Operating system " + os + " not yet supported");
 373                 }
 374             }
 375 
 376             if (isServer) {
 377                 RemoteDebuggerServer remote = null;
 378                 try {
 379                     remote = new RemoteDebuggerServer(debugger, rmiPort);
 380                 }
 381                 catch (RemoteException rem) {
 382                     throw new DebuggerException(rem);
 383                 }
 384                 RMIHelper.rebind(serverID, remote);
 385             }
 386         } else {
 387             //
 388             // Remote mode (client attaching to server)
 389             //
 390 
 391             // Create and install a security manager
 392 
 393             // FIXME: currently commented out because we were having
 394             // security problems since we're "in the sun.* hierarchy" here.
 395             // Perhaps a permissive policy file would work around this. In
 396             // the long run, will probably have to move into com.sun.*.
 397 
 398             //    if (System.getSecurityManager() == null) {
 399             //      System.setSecurityManager(new RMISecurityManager());
 400             //    }
 401 
 402             connectRemoteDebugger();
 403         }
 404     }
 405 
 406     private void setupVM() {
 407         // We need to instantiate a HotSpotTypeDataBase on both the client
 408         // and server machine. On the server it is only currently used to
 409         // configure the Java primitive type sizes (which we should
 410         // consider making constant). On the client it is used to
 411         // configure the VM.
 412 
 413         try {
 414             if (os.equals("solaris")) {
 415                 db = new HotSpotTypeDataBase(machDesc,
 416                 new HotSpotSolarisVtblAccess(debugger, jvmLibNames),
 417                 debugger, jvmLibNames);
 418             } else if (os.equals("win32")) {
 419                 db = new HotSpotTypeDataBase(machDesc,
 420                 new Win32VtblAccess(debugger, jvmLibNames),
 421                 debugger, jvmLibNames);
 422             } else if (os.equals("linux")) {
 423                 db = new HotSpotTypeDataBase(machDesc,
 424                 new LinuxVtblAccess(debugger, jvmLibNames),
 425                 debugger, jvmLibNames);
 426             } else if (os.equals("bsd")) {
 427                 db = new HotSpotTypeDataBase(machDesc,
 428                 new BsdVtblAccess(debugger, jvmLibNames),
 429                 debugger, jvmLibNames);
 430             } else if (os.equals("darwin")) {
 431                 db = new HotSpotTypeDataBase(machDesc,
 432                 new BsdVtblAccess(debugger, jvmLibNames),
 433                 debugger, jvmLibNames);
 434             } else {
 435                 throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)");
 436             }
 437         }
 438         catch (NoSuchSymbolException e) {
 439             throw new DebuggerException("Doesn't appear to be a HotSpot VM (could not find symbol \"" +
 440             e.getSymbol() + "\" in remote process)");
 441         }
 442 
 443         if (startupMode != REMOTE_MODE) {
 444             // Configure the debugger with the primitive type sizes just obtained from the VM
 445             debugger.configureJavaPrimitiveTypeSizes(db.getJBooleanType().getSize(),
 446             db.getJByteType().getSize(),
 447             db.getJCharType().getSize(),
 448             db.getJDoubleType().getSize(),
 449             db.getJFloatType().getSize(),
 450             db.getJIntType().getSize(),
 451             db.getJLongType().getSize(),
 452             db.getJShortType().getSize());
 453         }
 454 
 455         if (!isServer) {
 456             // Do not initialize the VM on the server (unnecessary, since it's
 457             // instantiated on the client)
 458             try {
 459                 VM.initialize(db, debugger);
 460             } catch (DebuggerException e) {
 461                 throw (e);
 462             } catch (Exception e) {
 463                 throw new DebuggerException(e);
 464             }
 465         }
 466     }
 467 
 468     //--------------------------------------------------------------------------------
 469     // OS-specific debugger setup/connect routines
 470     //
 471 
 472     // Use the existing JVMDebugger, as passed to our constructor.
 473     // Retrieve os and cpu from that debugger, not the current platform.
 474     private void setupDebuggerExisting() {
 475 
 476         os = debugger.getOS();
 477         cpu = debugger.getCPU();
 478         setupJVMLibNames(os);
 479         machDesc = debugger.getMachineDescription();
 480     }
 481 
 482     // Given a classname, load an alternate implementation of JVMDebugger.
 483     private void setupDebuggerAlternate(String alternateName) {
 484 
 485         try {
 486             Class<?> c = Class.forName(alternateName);
 487             Constructor cons = c.getConstructor();
 488             debugger = (JVMDebugger) cons.newInstance();
 489             attachDebugger();
 490             setupDebuggerExisting();
 491 
 492         } catch (ClassNotFoundException cnfe) {
 493             throw new DebuggerException("Cannot find alternate SA Debugger: '" + alternateName + "'");
 494         } catch (NoSuchMethodException nsme) {
 495             throw new DebuggerException("Alternate SA Debugger: '" + alternateName + "' has missing constructor.");
 496         } catch (InstantiationException ie) {
 497             throw new DebuggerException("Alternate SA Debugger: '" + alternateName + "' fails to initialise: ", ie);
 498         } catch (IllegalAccessException iae) {
 499             throw new DebuggerException("Alternate SA Debugger: '" + alternateName + "' fails to initialise: ", iae);
 500         } catch (InvocationTargetException iae) {
 501             throw new DebuggerException("Alternate SA Debugger: '" + alternateName + "' fails to initialise: ", iae);
 502         }
 503 
 504         System.err.println("Loaded alternate HotSpot SA Debugger: " + alternateName);
 505     }
 506 
 507     //
 508     // Solaris
 509     //
 510 
 511     private void setupDebuggerSolaris() {
 512         setupJVMLibNamesSolaris();
 513         ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true);
 514         debugger = dbg;
 515         attachDebugger();
 516 
 517         // Set up CPU-dependent stuff
 518         if (cpu.equals("x86")) {
 519             machDesc = new MachineDescriptionIntelX86();
 520         } else if (cpu.equals("sparc")) {
 521             int addressSize = dbg.getRemoteProcessAddressSize();
 522             if (addressSize == -1) {
 523                 throw new DebuggerException("Error occurred while trying to determine the remote process's " +
 524                                             "address size");
 525             }
 526 
 527             if (addressSize == 32) {
 528                 machDesc = new MachineDescriptionSPARC32Bit();
 529             } else if (addressSize == 64) {
 530                 machDesc = new MachineDescriptionSPARC64Bit();
 531             } else {
 532                 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC");
 533             }
 534         } else if (cpu.equals("amd64")) {
 535             machDesc = new MachineDescriptionAMD64();
 536         } else {
 537             throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64");
 538         }
 539 
 540         dbg.setMachineDescription(machDesc);
 541         return;
 542     }
 543 
 544     private void connectRemoteDebugger() throws DebuggerException {
 545         RemoteDebugger remote =
 546         (RemoteDebugger) RMIHelper.lookup(debugServerID);
 547         debugger = new RemoteDebuggerClient(remote);
 548         machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription();
 549         os = debugger.getOS();
 550         setupJVMLibNames(os);
 551         cpu = debugger.getCPU();
 552     }
 553 
 554     private void setupJVMLibNames(String os) {
 555         if (os.equals("solaris")) {
 556             setupJVMLibNamesSolaris();
 557         } else if (os.equals("win32")) {
 558             setupJVMLibNamesWin32();
 559         } else if (os.equals("linux")) {
 560             setupJVMLibNamesLinux();
 561         } else if (os.equals("bsd")) {
 562             setupJVMLibNamesBsd();
 563         } else if (os.equals("darwin")) {
 564             setupJVMLibNamesDarwin();
 565         } else {
 566             throw new RuntimeException("Unknown OS type");
 567         }
 568     }
 569 
 570     private void setupJVMLibNamesSolaris() {
 571         jvmLibNames = new String[] { "libjvm.so" };
 572     }
 573 
 574     //
 575     // Win32
 576     //
 577 
 578     private void setupDebuggerWin32() {
 579         setupJVMLibNamesWin32();
 580 
 581         if (cpu.equals("x86")) {
 582             machDesc = new MachineDescriptionIntelX86();
 583         } else if (cpu.equals("amd64")) {
 584             machDesc = new MachineDescriptionAMD64();
 585         } else {
 586             throw new DebuggerException("Win32 supported under x86 and amd64 only");
 587         }
 588 
 589         // Note we do not use a cache for the local debugger in server
 590         // mode; it will be taken care of on the client side (once remote
 591         // debugging is implemented).
 592 
 593         debugger = new WindbgDebuggerLocal(machDesc, !isServer);
 594 
 595         attachDebugger();
 596 
 597         // FIXME: add support for server mode
 598     }
 599 
 600     private void setupJVMLibNamesWin32() {
 601         jvmLibNames = new String[] { "jvm.dll" };
 602     }
 603 
 604     //
 605     // Linux
 606     //
 607 
 608     private void setupDebuggerLinux() {
 609         setupJVMLibNamesLinux();
 610 
 611         if (cpu.equals("x86")) {
 612             machDesc = new MachineDescriptionIntelX86();
 613         } else if (cpu.equals("amd64")) {
 614             machDesc = new MachineDescriptionAMD64();
 615         } else if (cpu.equals("ppc64")) {
 616             machDesc = new MachineDescriptionPPC64();
 617         } else if (cpu.equals("aarch64")) {
 618             machDesc = new MachineDescriptionAArch64();
 619         } else if (cpu.equals("sparc")) {
 620             if (LinuxDebuggerLocal.getAddressSize()==8) {
 621                     machDesc = new MachineDescriptionSPARC64Bit();
 622             } else {
 623                     machDesc = new MachineDescriptionSPARC32Bit();
 624             }
 625         } else {
 626           try {
 627             machDesc = (MachineDescription)
 628               Class.forName("sun.jvm.hotspot.debugger.MachineDescription" +
 629                             cpu.toUpperCase()).getDeclaredConstructor().newInstance();
 630           } catch (Exception e) {
 631             throw new DebuggerException("Linux not supported on machine type " + cpu);
 632           }
 633         }
 634 
 635         LinuxDebuggerLocal dbg =
 636         new LinuxDebuggerLocal(machDesc, !isServer);
 637         debugger = dbg;
 638 
 639         attachDebugger();
 640     }
 641 
 642     private void setupJVMLibNamesLinux() {
 643         jvmLibNames = new String[] { "libjvm.so" };
 644     }
 645 
 646     //
 647     // BSD
 648     //
 649 
 650     private void setupDebuggerBsd() {
 651         setupJVMLibNamesBsd();
 652 
 653         if (cpu.equals("x86")) {
 654             machDesc = new MachineDescriptionIntelX86();
 655         } else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
 656             machDesc = new MachineDescriptionAMD64();
 657         } else {
 658             throw new DebuggerException("BSD only supported on x86/x86_64. Current arch: " + cpu);
 659         }
 660 
 661         BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer);
 662         debugger = dbg;
 663 
 664         attachDebugger();
 665     }
 666 
 667     private void setupJVMLibNamesBsd() {
 668         jvmLibNames = new String[] { "libjvm.so" };
 669     }
 670 
 671     //
 672     // Darwin
 673     //
 674 
 675     private void setupDebuggerDarwin() {
 676         setupJVMLibNamesDarwin();
 677 
 678         if (cpu.equals("amd64") || cpu.equals("x86_64")) {
 679             machDesc = new MachineDescriptionAMD64();
 680         } else {
 681             throw new DebuggerException("Darwin only supported on x86_64. Current arch: " + cpu);
 682         }
 683 
 684         BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer);
 685         debugger = dbg;
 686 
 687         attachDebugger();
 688     }
 689 
 690     private void setupJVMLibNamesDarwin() {
 691         jvmLibNames = new String[] { "libjvm.dylib" };
 692     }
 693 
 694     /** Convenience routine which should be called by per-platform
 695       debugger setup. Should not be called when startupMode is
 696       REMOTE_MODE. */
 697     private void attachDebugger() {
 698         if (startupMode == PROCESS_MODE) {
 699             debugger.attach(pid);
 700         } else if (startupMode == CORE_FILE_MODE) {
 701             debugger.attach(javaExecutableName, coreFileName);
 702         } else {
 703             throw new DebuggerException("Should not call attach() for startupMode == " + startupMode);
 704         }
 705     }
 706 }