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