Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java @ 3945:8ed53447f690
Merge
author | iveresov |
---|---|
date | Thu, 15 Sep 2011 12:44:09 -0700 |
parents | f6f3bb0ee072 |
children | f08d439fab8c |
rev | line source |
---|---|
0 | 1 /* |
3939 | 2 * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 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(); | |
3939 | 628 ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true); |
629 debugger = dbg; | |
630 attachDebugger(); | |
0 | 631 |
3939 | 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"); | |
0 | 639 } |
640 | |
3939 | 641 if (addressSize == 32) { |
642 machDesc = new MachineDescriptionSPARC32Bit(); | |
643 } else if (addressSize == 64) { | |
644 machDesc = new MachineDescriptionSPARC64Bit(); | |
0 | 645 } else { |
3939 | 646 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); |
0 | 647 } |
3939 | 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 } | |
0 | 653 |
3939 | 654 dbg.setMachineDescription(machDesc); |
0 | 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 | |
3939 | 702 debugger = new WindbgDebuggerLocal(machDesc, !isServer); |
0 | 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 } |