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