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; 26 27 import java.io.PrintStream; 28 import java.net.*; 29 import java.rmi.*; 30 import sun.jvm.hotspot.debugger.*; 31 import sun.jvm.hotspot.debugger.dbx.*; 32 import sun.jvm.hotspot.debugger.proc.*; 33 import sun.jvm.hotspot.debugger.remote.*; 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.memory.*; 38 import sun.jvm.hotspot.oops.*; 39 import sun.jvm.hotspot.runtime.*; 40 import sun.jvm.hotspot.types.*; 41 import sun.jvm.hotspot.utilities.*; 42 43 /** <P> This class wraps much of the basic functionality and is the 44 * highest-level factory for VM data structures. It makes it simple 45 * to start up the debugging system. </P> 46 * 47 * <P> FIXME: need to add a way to configure the paths to dbx and the 48 * DSO from the outside. However, this should work for now for 49 * internal use. </P> 50 * 51 * <P> FIXME: especially with the addition of remote debugging, this 52 * has turned into a mess; needs rethinking. </P> 53 */ 54 55 public class HotSpotAgent { 56 private JVMDebugger debugger; 57 private MachineDescription machDesc; 58 private TypeDataBase db; 59 60 private String os; 61 private String cpu; 62 private String fileSep; 63 64 // The system can work in several ways: 65 // - Attaching to local process 66 // - Attaching to local core file 67 // - Connecting to remote debug server 68 // - Starting debug server for process 69 // - Starting debug server for core file 70 71 // These are options for the "client" side of things 72 private static final int PROCESS_MODE = 0; 73 private static final int CORE_FILE_MODE = 1; 74 private static final int REMOTE_MODE = 2; 75 private int startupMode; 76 77 // This indicates whether we are really starting a server or not 78 private boolean isServer; 79 80 // All possible required information for connecting 81 private int pid; 82 private String javaExecutableName; 83 private String coreFileName; 84 private String debugServerID; 85 86 // All needed information for server side 87 private String serverID; 88 89 private String[] jvmLibNames; 90 91 // FIXME: make these configurable, i.e., via a dotfile; also 92 // consider searching within the JDK from which this Java executable 93 // comes to find them 94 private static final String defaultDbxPathPrefix = "/net/jano.sfbay/export/disk05/hotspot/sa"; 95 private static final String defaultDbxSvcAgentDSOPathPrefix = "/net/jano.sfbay/export/disk05/hotspot/sa"; 96 97 static void showUsage() { 98 System.out.println(" You can also pass these -D options to java to specify where to find dbx and the \n" + 99 " Serviceability Agent plugin for dbx:"); 100 System.out.println(" -DdbxPathName=<path-to-dbx-executable>\n" + 101 " Default is derived from dbxPathPrefix"); 102 System.out.println(" or"); 103 System.out.println(" -DdbxPathPrefix=<xxx>\n" + 104 " where xxx is the path name of a dir structure that contains:\n" + 105 " <os>/<arch>/bin/dbx\n" + 106 " The default is " + defaultDbxPathPrefix); 107 System.out.println(" and"); 108 System.out.println(" -DdbxSvcAgentDSOPathName=<path-to-dbx-serviceability-agent-module>\n" + 109 " Default is determined from dbxSvcAgentDSOPathPrefix"); 110 System.out.println(" or"); 111 System.out.println(" -DdbxSvcAgentDSOPathPrefix=<xxx>\n" + 112 " where xxx is the pathname of a dir structure that contains:\n" + 113 " <os>/<arch>/bin/lib/libsvc_agent_dbx.so\n" + 114 " The default is " + defaultDbxSvcAgentDSOPathPrefix); 115 } 116 117 public HotSpotAgent() { 118 // for non-server add shutdown hook to clean-up debugger in case 119 // of forced exit. For remote server, shutdown hook is added by 120 // DebugServer. 121 Runtime.getRuntime().addShutdownHook(new java.lang.Thread( 122 new Runnable() { 123 public void run() { 124 synchronized (HotSpotAgent.this) { 125 if (!isServer) { 126 detach(); 127 } 128 } 129 } 130 })); 131 } 132 133 //-------------------------------------------------------------------------------- 134 // Accessors (once the system is set up) 419 try { 420 VM.initialize(db, debugger); 421 } catch (DebuggerException e) { 422 throw (e); 423 } catch (Exception e) { 424 throw new DebuggerException(e); 425 } 426 } 427 } 428 429 //-------------------------------------------------------------------------------- 430 // OS-specific debugger setup/connect routines 431 // 432 433 // 434 // Solaris 435 // 436 437 private void setupDebuggerSolaris() { 438 setupJVMLibNamesSolaris(); 439 if(System.getProperty("sun.jvm.hotspot.debugger.useProcDebugger") != null) { 440 ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true); 441 debugger = dbg; 442 attachDebugger(); 443 444 // Set up CPU-dependent stuff 445 if (cpu.equals("x86")) { 446 machDesc = new MachineDescriptionIntelX86(); 447 } else if (cpu.equals("sparc")) { 448 int addressSize = dbg.getRemoteProcessAddressSize(); 449 if (addressSize == -1) { 450 throw new DebuggerException("Error occurred while trying to determine the remote process's " + 451 "address size"); 452 } 453 454 if (addressSize == 32) { 455 machDesc = new MachineDescriptionSPARC32Bit(); 456 } else if (addressSize == 64) { 457 machDesc = new MachineDescriptionSPARC64Bit(); 458 } else { 459 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); 460 } 461 } else if (cpu.equals("amd64")) { 462 machDesc = new MachineDescriptionAMD64(); 463 } else { 464 throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64"); 465 } 466 467 dbg.setMachineDescription(machDesc); 468 return; 469 470 } else { 471 String dbxPathName; 472 String dbxPathPrefix; 473 String dbxSvcAgentDSOPathName; 474 String dbxSvcAgentDSOPathPrefix; 475 String[] dbxSvcAgentDSOPathNames = null; 476 477 // use path names/prefixes specified on command 478 dbxPathName = System.getProperty("dbxPathName"); 479 if (dbxPathName == null) { 480 dbxPathPrefix = System.getProperty("dbxPathPrefix"); 481 if (dbxPathPrefix == null) { 482 dbxPathPrefix = defaultDbxPathPrefix; 483 } 484 dbxPathName = dbxPathPrefix + fileSep + os + fileSep + cpu + fileSep + "bin" + fileSep + "dbx"; 485 } 486 487 dbxSvcAgentDSOPathName = System.getProperty("dbxSvcAgentDSOPathName"); 488 if (dbxSvcAgentDSOPathName != null) { 489 dbxSvcAgentDSOPathNames = new String[] { dbxSvcAgentDSOPathName } ; 490 } else { 491 dbxSvcAgentDSOPathPrefix = System.getProperty("dbxSvcAgentDSOPathPrefix"); 492 if (dbxSvcAgentDSOPathPrefix == null) { 493 dbxSvcAgentDSOPathPrefix = defaultDbxSvcAgentDSOPathPrefix; 494 } 495 if (cpu.equals("sparc")) { 496 dbxSvcAgentDSOPathNames = new String[] { 497 // FIXME: bad hack for SPARC v9. This is necessary because 498 // there are two dbx executables on SPARC, one for v8 and one 499 // for v9, and it isn't obvious how to tell the two apart 500 // using the dbx command line. See 501 // DbxDebuggerLocal.importDbxModule(). 502 dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + "v9" + fileSep + "lib" + 503 fileSep + "libsvc_agent_dbx.so", 504 dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + fileSep + "lib" + 505 fileSep + "libsvc_agent_dbx.so", 506 }; 507 } else { 508 dbxSvcAgentDSOPathNames = new String[] { 509 dbxSvcAgentDSOPathPrefix + fileSep + os + fileSep + cpu + fileSep + "lib" + 510 fileSep + "libsvc_agent_dbx.so" 511 }; 512 } 513 } 514 515 // Note we do not use a cache for the local debugger in server 516 // mode; it's taken care of on the client side 517 DbxDebuggerLocal dbg = new DbxDebuggerLocal(null, dbxPathName, dbxSvcAgentDSOPathNames, !isServer); 518 debugger = dbg; 519 520 attachDebugger(); 521 522 // Set up CPU-dependent stuff 523 if (cpu.equals("x86")) { 524 machDesc = new MachineDescriptionIntelX86(); 525 } else if (cpu.equals("sparc")) { 526 int addressSize = dbg.getRemoteProcessAddressSize(); 527 if (addressSize == -1) { 528 throw new DebuggerException("Error occurred while trying to determine the remote process's " + 529 "address size. It's possible that the Serviceability Agent's dbx module failed to " + 530 "initialize. Examine the standard output and standard error streams from the dbx " + 531 "process for more information."); 532 } 533 534 if (addressSize == 32) { 535 machDesc = new MachineDescriptionSPARC32Bit(); 536 } else if (addressSize == 64) { 537 machDesc = new MachineDescriptionSPARC64Bit(); 538 } else { 539 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); 540 } 541 } 542 543 dbg.setMachineDescription(machDesc); 544 545 } 546 } 547 548 private void connectRemoteDebugger() throws DebuggerException { 549 RemoteDebugger remote = 550 (RemoteDebugger) RMIHelper.lookup(debugServerID); 551 debugger = new RemoteDebuggerClient(remote); 552 machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription(); 553 os = debugger.getOS(); 554 if (os.equals("solaris")) { 555 setupJVMLibNamesSolaris(); 556 } else if (os.equals("win32")) { 557 setupJVMLibNamesWin32(); 558 } else if (os.equals("linux")) { 559 setupJVMLibNamesLinux(); 560 } else { 561 throw new RuntimeException("Unknown OS type"); 562 } 563 564 cpu = debugger.getCPU(); 565 } 566 567 private void setupJVMLibNamesSolaris() { | 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; 26 27 import java.io.PrintStream; 28 import java.net.*; 29 import java.rmi.*; 30 import sun.jvm.hotspot.debugger.*; 31 import sun.jvm.hotspot.debugger.proc.*; 32 import sun.jvm.hotspot.debugger.remote.*; 33 import sun.jvm.hotspot.debugger.win32.*; 34 import sun.jvm.hotspot.debugger.windbg.*; 35 import sun.jvm.hotspot.debugger.linux.*; 36 import sun.jvm.hotspot.memory.*; 37 import sun.jvm.hotspot.oops.*; 38 import sun.jvm.hotspot.runtime.*; 39 import sun.jvm.hotspot.types.*; 40 import sun.jvm.hotspot.utilities.*; 41 42 /** <P> This class wraps much of the basic functionality and is the 43 * highest-level factory for VM data structures. It makes it simple 44 * to start up the debugging system. </P> 45 * 46 * <P> FIXME: especially with the addition of remote debugging, this 47 * has turned into a mess; needs rethinking. </P> 48 */ 49 50 public class HotSpotAgent { 51 private JVMDebugger debugger; 52 private MachineDescription machDesc; 53 private TypeDataBase db; 54 55 private String os; 56 private String cpu; 57 private String fileSep; 58 59 // The system can work in several ways: 60 // - Attaching to local process 61 // - Attaching to local core file 62 // - Connecting to remote debug server 63 // - Starting debug server for process 64 // - Starting debug server for core file 65 66 // These are options for the "client" side of things 67 private static final int PROCESS_MODE = 0; 68 private static final int CORE_FILE_MODE = 1; 69 private static final int REMOTE_MODE = 2; 70 private int startupMode; 71 72 // This indicates whether we are really starting a server or not 73 private boolean isServer; 74 75 // All possible required information for connecting 76 private int pid; 77 private String javaExecutableName; 78 private String coreFileName; 79 private String debugServerID; 80 81 // All needed information for server side 82 private String serverID; 83 84 private String[] jvmLibNames; 85 86 static void showUsage() { 87 } 88 89 public HotSpotAgent() { 90 // for non-server add shutdown hook to clean-up debugger in case 91 // of forced exit. For remote server, shutdown hook is added by 92 // DebugServer. 93 Runtime.getRuntime().addShutdownHook(new java.lang.Thread( 94 new Runnable() { 95 public void run() { 96 synchronized (HotSpotAgent.this) { 97 if (!isServer) { 98 detach(); 99 } 100 } 101 } 102 })); 103 } 104 105 //-------------------------------------------------------------------------------- 106 // Accessors (once the system is set up) 391 try { 392 VM.initialize(db, debugger); 393 } catch (DebuggerException e) { 394 throw (e); 395 } catch (Exception e) { 396 throw new DebuggerException(e); 397 } 398 } 399 } 400 401 //-------------------------------------------------------------------------------- 402 // OS-specific debugger setup/connect routines 403 // 404 405 // 406 // Solaris 407 // 408 409 private void setupDebuggerSolaris() { 410 setupJVMLibNamesSolaris(); 411 ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true); 412 debugger = dbg; 413 attachDebugger(); 414 415 // Set up CPU-dependent stuff 416 if (cpu.equals("x86")) { 417 machDesc = new MachineDescriptionIntelX86(); 418 } else if (cpu.equals("sparc")) { 419 int addressSize = dbg.getRemoteProcessAddressSize(); 420 if (addressSize == -1) { 421 throw new DebuggerException("Error occurred while trying to determine the remote process's " + 422 "address size"); 423 } 424 425 if (addressSize == 32) { 426 machDesc = new MachineDescriptionSPARC32Bit(); 427 } else if (addressSize == 64) { 428 machDesc = new MachineDescriptionSPARC64Bit(); 429 } else { 430 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); 431 } 432 } else if (cpu.equals("amd64")) { 433 machDesc = new MachineDescriptionAMD64(); 434 } else { 435 throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64"); 436 } 437 438 dbg.setMachineDescription(machDesc); 439 } 440 441 private void connectRemoteDebugger() throws DebuggerException { 442 RemoteDebugger remote = 443 (RemoteDebugger) RMIHelper.lookup(debugServerID); 444 debugger = new RemoteDebuggerClient(remote); 445 machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription(); 446 os = debugger.getOS(); 447 if (os.equals("solaris")) { 448 setupJVMLibNamesSolaris(); 449 } else if (os.equals("win32")) { 450 setupJVMLibNamesWin32(); 451 } else if (os.equals("linux")) { 452 setupJVMLibNamesLinux(); 453 } else { 454 throw new RuntimeException("Unknown OS type"); 455 } 456 457 cpu = debugger.getCPU(); 458 } 459 460 private void setupJVMLibNamesSolaris() { |