| /* |
| * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| package sun.jvm.hotspot.bugspot; |
| |
| import java.io.PrintStream; |
| import java.net.*; |
| import java.rmi.*; |
| import sun.jvm.hotspot.*; |
| import sun.jvm.hotspot.debugger.*; |
| import sun.jvm.hotspot.debugger.bsd.*; |
| import sun.jvm.hotspot.debugger.proc.*; |
| import sun.jvm.hotspot.debugger.cdbg.*; |
| import sun.jvm.hotspot.debugger.windbg.*; |
| import sun.jvm.hotspot.debugger.linux.*; |
| import sun.jvm.hotspot.debugger.sparc.*; |
| import sun.jvm.hotspot.debugger.remote.*; |
| import sun.jvm.hotspot.livejvm.*; |
| import sun.jvm.hotspot.memory.*; |
| import sun.jvm.hotspot.oops.*; |
| import sun.jvm.hotspot.runtime.*; |
| import sun.jvm.hotspot.types.*; |
| import sun.jvm.hotspot.utilities.*; |
| |
| /** <P> This class wraps the basic functionality for connecting to the |
| * target process or debug server. It makes it simple to start up the |
| * debugging system. </P> |
| * |
| * <P> This agent (as compared to the HotSpotAgent) can connect to |
| * and interact with arbitrary processes. If the target process |
| * happens to be a HotSpot JVM, the Java debugging features of the |
| * Serviceability Agent are enabled. Further, if the Serviceability |
| * Agent's JVMDI module is loaded into the target VM, interaction |
| * with the live Java program is possible, specifically the catching |
| * of exceptions and setting of breakpoints. </P> |
| * |
| * <P> The BugSpot debugger requires that the underlying Debugger |
| * support C/C++ debugging via the CDebugger interface. </P> |
| * |
| * <P> FIXME: especially with the addition of remote debugging, this |
| * has turned into a mess; needs rethinking. </P> */ |
| |
| public class BugSpotAgent { |
| |
| private JVMDebugger debugger; |
| private MachineDescription machDesc; |
| private TypeDataBase db; |
| |
| private String os; |
| private String cpu; |
| private String fileSep; |
| |
| // The system can work in several ways: |
| // - Attaching to local process |
| // - Attaching to local core file |
| // - Connecting to remote debug server |
| // - Starting debug server for process |
| // - Starting debug server for core file |
| |
| // These are options for the "client" side of things |
| private static final int PROCESS_MODE = 0; |
| private static final int CORE_FILE_MODE = 1; |
| private static final int REMOTE_MODE = 2; |
| private int startupMode; |
| |
| // This indicates whether we are really starting a server or not |
| private boolean isServer; |
| |
| // All possible required information for connecting |
| private int pid; |
| private String executableName; |
| private String coreFileName; |
| private String debugServerID; |
| |
| // All needed information for server side |
| private String serverID; |
| |
| // Indicates whether we are attached to a HotSpot JVM or not |
| private boolean javaMode; |
| |
| // Indicates whether we have process control over a live HotSpot JVM |
| // or not; non-null if so. |
| private ServiceabilityAgentJVMDIModule jvmdi; |
| // While handling C breakpoints interactivity with the Java program |
| // is forbidden. Too many invariants are broken while the target is |
| // stopped at a C breakpoint to risk making JVMDI calls. |
| private boolean javaInteractionDisabled; |
| |
| private String[] jvmLibNames; |
| private String[] saLibNames; |
| |
| // FIXME: make these configurable, i.e., via a dotfile; also |
| // consider searching within the JDK from which this Java executable |
| // comes to find them |
| private static final String defaultDbxPathPrefix = "/net/jano.eng/export/disk05/hotspot/sa"; |
| private static final String defaultDbxSvcAgentDSOPathPrefix = "/net/jano.eng/export/disk05/hotspot/sa"; |
| |
| private static final boolean DEBUG; |
| static { |
| DEBUG = System.getProperty("sun.jvm.hotspot.bugspot.BugSpotAgent.DEBUG") |
| != null; |
| } |
| |
| static void debugPrintln(String str) { |
| if (DEBUG) { |
| System.err.println(str); |
| } |
| } |
| |
| static void showUsage() { |
| System.out.println(" You can also pass these -D options to java to specify where to find dbx and the \n" + |
| " Serviceability Agent plugin for dbx:"); |
| System.out.println(" -DdbxPathName=<path-to-dbx-executable>\n" + |
| " Default is derived from dbxPathPrefix"); |
| System.out.println(" or"); |
| System.out.println(" -DdbxPathPrefix=<xxx>\n" + |
| " where xxx is the path name of a dir structure that contains:\n" + |
| " <os>/<arch>/bin/dbx\n" + |
| " The default is " + defaultDbxPathPrefix); |
| System.out.println(" and"); |
| System.out.println(" -DdbxSvcAgentDSOPathName=<path-to-dbx-serviceability-agent-module>\n" + |
| " Default is determined from dbxSvcAgentDSOPathPrefix"); |
| System.out.println(" or"); |
| System.out.println(" -DdbxSvcAgentDSOPathPrefix=<xxx>\n" + |
| " where xxx is the pathname of a dir structure that contains:\n" + |
| " <os>/<arch>/bin/lib/libsvc_agent_dbx.so\n" + |
| " The default is " + defaultDbxSvcAgentDSOPathPrefix); |
| } |
| |
| public BugSpotAgent() { |
| // for non-server add shutdown hook to clean-up debugger in case |
| // of forced exit. For remote server, shutdown hook is added by |
| // DebugServer. |
| Runtime.getRuntime().addShutdownHook(new java.lang.Thread( |
| new Runnable() { |
| public void run() { |
| synchronized (BugSpotAgent.this) { |
| if (!isServer) { |
| detach(); |
| } |
| } |
| } |
| })); |
| } |
| |
| //-------------------------------------------------------------------------------- |
| // Accessors (once the system is set up) |
| // |
| |
| public synchronized Debugger getDebugger() { |
| return debugger; |
| } |
| |
| public synchronized CDebugger getCDebugger() { |
| return getDebugger().getCDebugger(); |
| } |
| |
| public synchronized ProcessControl getProcessControl() { |
| return getCDebugger().getProcessControl(); |
| } |
| |
| public synchronized TypeDataBase getTypeDataBase() { |
| return db; |
| } |
| |
| /** Indicates whether the target process is suspended |
| completely. Equivalent to getProcessControl().isSuspended(). */ |
| public synchronized boolean isSuspended() throws DebuggerException { |
| return getProcessControl().isSuspended(); |
| } |
| |
| /** Suspends the target process completely. Equivalent to |
| getProcessControl().suspend(). */ |
| public synchronized void suspend() throws DebuggerException { |
| getProcessControl().suspend(); |
| } |
| |
| /** Resumes the target process completely. Equivalent to |
| getProcessControl().suspend(). */ |
| public synchronized void resume() throws DebuggerException { |
| getProcessControl().resume(); |
| } |
| |
| /** Indicates whether we are attached to a Java HotSpot virtual |
| machine */ |
| public synchronized boolean isJavaMode() { |
| return javaMode; |
| } |
| |
| /** Temporarily disables interaction with the target process via |
| JVMDI. This is done while the target process is stopped at a C |
| breakpoint. Can be called even if the JVMDI agent has not been |
| initialized. */ |
| public synchronized void disableJavaInteraction() { |
| javaInteractionDisabled = true; |
| } |
| |
| /** Re-enables interaction with the target process via JVMDI. This |
| is done while the target process is continued past a C |
| braekpoint. Can be called even if the JVMDI agent has not been |
| initialized. */ |
| public synchronized void enableJavaInteraction() { |
| javaInteractionDisabled = false; |
| } |
| |
| /** Indicates whether Java interaction has been disabled */ |
| public synchronized boolean isJavaInteractionDisabled() { |
| return javaInteractionDisabled; |
| } |
| |
| /** Indicates whether we can talk to the Serviceability Agent's |
| JVMDI module to be able to set breakpoints */ |
| public synchronized boolean canInteractWithJava() { |
| return (jvmdi != null) && !javaInteractionDisabled; |
| } |
| |
| /** Suspends all Java threads in the target process. Can only be |
| called if we are attached to a HotSpot JVM and can connect to |
| the SA's JVMDI module. Must not be called when the target |
| process has been suspended with suspend(). */ |
| public synchronized void suspendJava() throws DebuggerException { |
| if (!canInteractWithJava()) { |
| throw new DebuggerException("Could not connect to SA's JVMDI module"); |
| } |
| if (jvmdi.isSuspended()) { |
| throw new DebuggerException("Target process already suspended via JVMDI"); |
| } |
| jvmdi.suspend(); |
| } |
| |
| /** Resumes all Java threads in the target process. Can only be |
| called if we are attached to a HotSpot JVM and can connect to |
| the SA's JVMDI module. Must not be called when the target |
| process has been suspended with suspend(). */ |
| public synchronized void resumeJava() throws DebuggerException { |
| if (!canInteractWithJava()) { |
| throw new DebuggerException("Could not connect to SA's JVMDI module"); |
| } |
| if (!jvmdi.isSuspended()) { |
| throw new DebuggerException("Target process already resumed via JVMDI"); |
| } |
| jvmdi.resume(); |
| } |
| |
| /** Indicates whether the target process has been suspended at the |
| Java language level via the SA's JVMDI module */ |
| public synchronized boolean isJavaSuspended() throws DebuggerException { |
| return jvmdi.isSuspended(); |
| } |
| |
| /** Toggle a Java breakpoint at the given location. */ |
| public synchronized ServiceabilityAgentJVMDIModule.BreakpointToggleResult |
| toggleJavaBreakpoint(String srcFileName, |
| String pkgName, |
| int lineNo) { |
| if (!canInteractWithJava()) { |
| throw new DebuggerException("Could not connect to SA's JVMDI module; can not toggle Java breakpoints"); |
| } |
| return jvmdi.toggleBreakpoint(srcFileName, pkgName, lineNo); |
| } |
| |
| /** Access to JVMDI module's eventPending */ |
| public synchronized boolean javaEventPending() throws DebuggerException { |
| if (!canInteractWithJava()) { |
| throw new DebuggerException("Could not connect to SA's JVMDI module; can not poll for Java debug events"); |
| } |
| return jvmdi.eventPending(); |
| } |
| |
| /** Access to JVMDI module's eventPoll */ |
| public synchronized Event javaEventPoll() throws DebuggerException { |
| if (!canInteractWithJava()) { |
| throw new DebuggerException("Could not connect to SA's JVMDI module; can not poll for Java debug events"); |
| } |
| return jvmdi.eventPoll(); |
| } |
| |
| /** Access to JVMDI module's eventContinue */ |
| public synchronized void javaEventContinue() throws DebuggerException { |
| if (!canInteractWithJava()) { |
| throw new DebuggerException("Could not connect to SA's JVMDI module; can not continue past Java debug events"); |
| } |
| jvmdi.eventContinue(); |
| } |
| |
| |
| // FIXME: add other accessors. For example, suspension and |
| // resumption should be done through this interface, as well as |
| // interaction with the live Java process such as breakpoint setting. |
| // Probably should not expose the ServiceabilityAgentJVMDIModule |
| // from this interface. |
| |
| //-------------------------------------------------------------------------------- |
| // Client-side operations |
| // |
| |
| /** This attaches to a process running on the local machine. */ |
| public synchronized void attach(int processID) |
| throws DebuggerException { |
| if (debugger != null) { |
| throw new DebuggerException("Already attached"); |
| } |
| pid = processID; |
| startupMode = PROCESS_MODE; |
| isServer = false; |
| go(); |
| } |
| |
| /** This opens a core file on the local machine */ |
| public synchronized void attach(String executableName, String coreFileName) |
| throws DebuggerException { |
| if (debugger != null) { |
| throw new DebuggerException("Already attached"); |
| } |
| if ((executableName == null) || (coreFileName == null)) { |
| throw new DebuggerException("Both the core file name and executable name must be specified"); |
| } |
| this.executableName = executableName; |
| this.coreFileName = coreFileName; |
| startupMode = CORE_FILE_MODE; |
| isServer = false; |
| go(); |
| } |
| |
| /** This attaches to a "debug server" on a remote machine; this |
| remote server has already attached to a process or opened a |
| core file and is waiting for RMI calls on the Debugger object to |
| come in. */ |
| public synchronized void attach(String remoteServerID) |
| throws DebuggerException { |
| if (debugger != null) { |
| throw new DebuggerException("Already attached to a process"); |
| } |
| if (remoteServerID == null) { |
| throw new DebuggerException("Debug server id must be specified"); |
| } |
| |
| debugServerID = remoteServerID; |
| startupMode = REMOTE_MODE; |
| isServer = false; |
| go(); |
| } |
| |
| /** This should only be called by the user on the client machine, |
| not the server machine */ |
| public synchronized boolean detach() throws DebuggerException { |
| if (isServer) { |
| throw new DebuggerException("Should not call detach() for server configuration"); |
| } |
| return detachInternal(); |
| } |
| |
| //-------------------------------------------------------------------------------- |
| // Server-side operations |
| // |
| |
| /** This attaches to a process running on the local machine and |
| starts a debug server, allowing remote machines to connect and |
| examine this process. uniqueID is used to uniquely identify the |
| debuggee */ |
| public synchronized void startServer(int processID, String uniqueID) |
| throws DebuggerException { |
| if (debugger != null) { |
| throw new DebuggerException("Already attached"); |
| } |
| pid = processID; |
| startupMode = PROCESS_MODE; |
| isServer = true; |
| serverID = uniqueID; |
| go(); |
| } |
| |
| /** This attaches to a process running on the local machine and |
| starts a debug server, allowing remote machines to connect and |
| examine this process. */ |
| public synchronized void startServer(int processID) |
| throws DebuggerException { |
| startServer(processID, null); |
| } |
| |
| /** This opens a core file on the local machine and starts a debug |
| server, allowing remote machines to connect and examine this |
| core file. uniqueID is used to uniquely identify the |
| debuggee */ |
| public synchronized void startServer(String executableName, String coreFileName, |
| String uniqueID) |
| throws DebuggerException { |
| if (debugger != null) { |
| throw new DebuggerException("Already attached"); |
| } |
| if ((executableName == null) || (coreFileName == null)) { |
| throw new DebuggerException("Both the core file name and Java executable name must be specified"); |
| } |
| this.executableName = executableName; |
| this.coreFileName = coreFileName; |
| startupMode = CORE_FILE_MODE; |
| isServer = true; |
| serverID = uniqueID; |
| go(); |
| } |
| |
| /** This opens a core file on the local machine and starts a debug |
| server, allowing remote machines to connect and examine this |
| core file.*/ |
| public synchronized void startServer(String executableName, String coreFileName) |
| throws DebuggerException { |
| startServer(executableName, coreFileName, null); |
| } |
| |
| /** This may only be called on the server side after startServer() |
| has been called */ |
| public synchronized boolean shutdownServer() throws DebuggerException { |
| if (!isServer) { |
| throw new DebuggerException("Should not call shutdownServer() for client configuration"); |
| } |
| return detachInternal(); |
| } |
| |
| |
| //-------------------------------------------------------------------------------- |
| // Internals only below this point |
| // |
| |
| private boolean detachInternal() { |
| if (debugger == null) { |
| return false; |
| } |
| if (canInteractWithJava()) { |
| jvmdi.detach(); |
| jvmdi = null; |
| } |
| boolean retval = true; |
| if (!isServer) { |
| VM.shutdown(); |
| } |
| // We must not call detach() if we are a client and are connected |
| // to a remote debugger |
| Debugger dbg = null; |
| DebuggerException ex = null; |
| if (isServer) { |
| try { |
| RMIHelper.unbind(serverID); |
| } |
| catch (DebuggerException de) { |
| ex = de; |
| } |
| dbg = debugger; |
| } else { |
| if (startupMode != REMOTE_MODE) { |
| dbg = debugger; |
| } |
| } |
| if (dbg != null) { |
| retval = dbg.detach(); |
| } |
| |
| debugger = null; |
| machDesc = null; |
| db = null; |
| if (ex != null) { |
| throw(ex); |
| } |
| return retval; |
| } |
| |
| private void go() { |
| setupDebugger(); |
| javaMode = setupVM(); |
| } |
| |
| private void setupDebugger() { |
| if (startupMode != REMOTE_MODE) { |
| // |
| // Local mode (client attaching to local process or setting up |
| // server, but not client attaching to server) |
| // |
| |
| try { |
| os = PlatformInfo.getOS(); |
| cpu = PlatformInfo.getCPU(); |
| } |
| catch (UnsupportedPlatformException e) { |
| throw new DebuggerException(e); |
| } |
| fileSep = System.getProperty("file.separator"); |
| |
| if (os.equals("solaris")) { |
| setupDebuggerSolaris(); |
| } else if (os.equals("win32")) { |
| setupDebuggerWin32(); |
| } else if (os.equals("linux")) { |
| setupDebuggerLinux(); |
| } else if (os.equals("bsd")) { |
| setupDebuggerBsd(); |
| } else { |
| // Add support for more operating systems here |
| throw new DebuggerException("Operating system " + os + " not yet supported"); |
| } |
| if (isServer) { |
| RemoteDebuggerServer remote = null; |
| try { |
| remote = new RemoteDebuggerServer(debugger); |
| } |
| catch (RemoteException rem) { |
| throw new DebuggerException(rem); |
| } |
| RMIHelper.rebind(serverID, remote); |
| } |
| } else { |
| // |
| // Remote mode (client attaching to server) |
| // |
| |
| // Create and install a security manager |
| |
| // FIXME: currently commented out because we were having |
| // security problems since we're "in the sun.* hierarchy" here. |
| // Perhaps a permissive policy file would work around this. In |
| // the long run, will probably have to move into com.sun.*. |
| |
| // if (System.getSecurityManager() == null) { |
| // System.setSecurityManager(new RMISecurityManager()); |
| // } |
| |
| connectRemoteDebugger(); |
| } |
| } |
| |
| private boolean setupVM() { |
| // We need to instantiate a HotSpotTypeDataBase on both the client |
| // and server machine. On the server it is only currently used to |
| // configure the Java primitive type sizes (which we should |
| // consider making constant). On the client it is used to |
| // configure the VM. |
| |
| try { |
| if (os.equals("solaris")) { |
| db = new HotSpotTypeDataBase(machDesc, new HotSpotSolarisVtblAccess(debugger, jvmLibNames), |
| debugger, jvmLibNames); |
| } else if (os.equals("win32")) { |
| db = new HotSpotTypeDataBase(machDesc, new Win32VtblAccess(debugger, jvmLibNames), |
| debugger, jvmLibNames); |
| } else if (os.equals("linux")) { |
| db = new HotSpotTypeDataBase(machDesc, new LinuxVtblAccess(debugger, jvmLibNames), |
| debugger, jvmLibNames); |
| } else if (os.equals("bsd")) { |
| db = new HotSpotTypeDataBase(machDesc, new BsdVtblAccess(debugger, jvmLibNames), |
| debugger, jvmLibNames); |
| } else { |
| throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess implemented yet)"); |
| } |
| } |
| catch (NoSuchSymbolException e) { |
| e.printStackTrace(); |
| return false; |
| } |
| |
| if (startupMode != REMOTE_MODE) { |
| // Configure the debugger with the primitive type sizes just obtained from the VM |
| debugger.configureJavaPrimitiveTypeSizes(db.getJBooleanType().getSize(), |
| db.getJByteType().getSize(), |
| db.getJCharType().getSize(), |
| db.getJDoubleType().getSize(), |
| db.getJFloatType().getSize(), |
| db.getJIntType().getSize(), |
| db.getJLongType().getSize(), |
| db.getJShortType().getSize()); |
| } |
| |
| if (!isServer) { |
| // Do not initialize the VM on the server (unnecessary, since it's |
| // instantiated on the client) |
| VM.initialize(db, debugger); |
| } |
| |
| try { |
| jvmdi = new ServiceabilityAgentJVMDIModule(debugger, saLibNames); |
| if (jvmdi.canAttach()) { |
| jvmdi.attach(); |
| jvmdi.setCommandTimeout(6000); |
| debugPrintln("Attached to Serviceability Agent's JVMDI module."); |
| // Jog VM to suspended point with JVMDI module |
| resume(); |
| suspendJava(); |
| suspend(); |
| debugPrintln("Suspended all Java threads."); |
| } else { |
| debugPrintln("Could not locate SA's JVMDI module; skipping attachment"); |
| jvmdi = null; |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| jvmdi = null; |
| } |
| |
| return true; |
| } |
| |
| //-------------------------------------------------------------------------------- |
| // OS-specific debugger setup/connect routines |
| // |
| |
| // |
| // Solaris |
| // |
| |
| private void setupDebuggerSolaris() { |
| setupJVMLibNamesSolaris(); |
| ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true); |
| debugger = dbg; |
| attachDebugger(); |
| |
| // Set up CPU-dependent stuff |
| if (cpu.equals("x86")) { |
| machDesc = new MachineDescriptionIntelX86(); |
| } else if (cpu.equals("sparc")) { |
| int addressSize = dbg.getRemoteProcessAddressSize(); |
| if (addressSize == -1) { |
| throw new DebuggerException("Error occurred while trying to determine the remote process's address size"); |
| } |
| |
| if (addressSize == 32) { |
| machDesc = new MachineDescriptionSPARC32Bit(); |
| } else if (addressSize == 64) { |
| machDesc = new MachineDescriptionSPARC64Bit(); |
| } else { |
| throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); |
| } |
| } else if (cpu.equals("amd64")) { |
| machDesc = new MachineDescriptionAMD64(); |
| } else { |
| throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64"); |
| } |
| |
| dbg.setMachineDescription(machDesc); |
| } |
| |
| private void connectRemoteDebugger() throws DebuggerException { |
| RemoteDebugger remote = |
| (RemoteDebugger) RMIHelper.lookup(debugServerID); |
| debugger = new RemoteDebuggerClient(remote); |
| machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription(); |
| os = debugger.getOS(); |
| if (os.equals("solaris")) { |
| setupJVMLibNamesSolaris(); |
| } else if (os.equals("win32")) { |
| setupJVMLibNamesWin32(); |
| } else if (os.equals("linux")) { |
| setupJVMLibNamesLinux(); |
| } else if (os.equals("bsd")) { |
| setupJVMLibNamesBsd(); |
| } else { |
| throw new RuntimeException("Unknown OS type"); |
| } |
| |
| cpu = debugger.getCPU(); |
| } |
| |
| private void setupJVMLibNamesSolaris() { |
| jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" }; |
| saLibNames = new String[] { "libsa.so", "libsa_g.so" }; |
| } |
| |
| // |
| // Win32 |
| // |
| |
| private void setupDebuggerWin32() { |
| setupJVMLibNamesWin32(); |
| |
| if (cpu.equals("x86")) { |
| machDesc = new MachineDescriptionIntelX86(); |
| } else if (cpu.equals("amd64")) { |
| machDesc = new MachineDescriptionAMD64(); |
| } else if (cpu.equals("ia64")) { |
| machDesc = new MachineDescriptionIA64(); |
| } else { |
| throw new DebuggerException("Win32 supported under x86, amd64 and ia64 only"); |
| } |
| |
| // Note we do not use a cache for the local debugger in server |
| // mode; it will be taken care of on the client side (once remote |
| // debugging is implemented). |
| |
| debugger = new WindbgDebuggerLocal(machDesc, !isServer); |
| |
| attachDebugger(); |
| } |
| |
| private void setupJVMLibNamesWin32() { |
| jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" }; |
| saLibNames = new String[] { "sa.dll", "sa_g.dll" }; |
| } |
| |
| // |
| // Linux |
| // |
| |
| private void setupDebuggerLinux() { |
| setupJVMLibNamesLinux(); |
| |
| if (cpu.equals("x86")) { |
| machDesc = new MachineDescriptionIntelX86(); |
| } else if (cpu.equals("ia64")) { |
| machDesc = new MachineDescriptionIA64(); |
| } else if (cpu.equals("amd64")) { |
| machDesc = new MachineDescriptionAMD64(); |
| } else if (cpu.equals("sparc")) { |
| if (LinuxDebuggerLocal.getAddressSize()==8) { |
| machDesc = new MachineDescriptionSPARC64Bit(); |
| } else { |
| machDesc = new MachineDescriptionSPARC32Bit(); |
| } |
| } else { |
| try { |
| machDesc = (MachineDescription) |
| Class.forName("sun.jvm.hotspot.debugger.MachineDescription" + |
| cpu.toUpperCase()).newInstance(); |
| } catch (Exception e) { |
| throw new DebuggerException("unsupported machine type"); |
| } |
| } |
| |
| |
| // Note we do not use a cache for the local debugger in server |
| // mode; it will be taken care of on the client side (once remote |
| // debugging is implemented). |
| |
| debugger = new LinuxDebuggerLocal(machDesc, !isServer); |
| attachDebugger(); |
| } |
| |
| private void setupJVMLibNamesLinux() { |
| // same as solaris |
| setupJVMLibNamesSolaris(); |
| } |
| |
| // |
| // BSD |
| // |
| |
| private void setupDebuggerBsd() { |
| setupJVMLibNamesBsd(); |
| |
| if (cpu.equals("x86")) { |
| machDesc = new MachineDescriptionIntelX86(); |
| } else if (cpu.equals("amd64") || (cpu.equals("x86_64"))) { |
| machDesc = new MachineDescriptionAMD64(); |
| } else { |
| throw new DebuggerException("Bsd only supported on x86/x86_64. Current arch: " + cpu); |
| } |
| |
| // Note we do not use a cache for the local debugger in server |
| // mode; it will be taken care of on the client side (once remote |
| // debugging is implemented). |
| |
| debugger = new BsdDebuggerLocal(machDesc, !isServer); |
| attachDebugger(); |
| } |
| |
| private void setupJVMLibNamesBsd() { |
| // same as solaris |
| setupJVMLibNamesSolaris(); |
| } |
| |
| /** Convenience routine which should be called by per-platform |
| debugger setup. Should not be called when startupMode is |
| REMOTE_MODE. */ |
| private void attachDebugger() { |
| if (startupMode == PROCESS_MODE) { |
| debugger.attach(pid); |
| } else if (startupMode == CORE_FILE_MODE) { |
| debugger.attach(executableName, coreFileName); |
| } else { |
| throw new DebuggerException("Should not call attach() for startupMode == " + startupMode); |
| } |
| } |
| } |