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