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