Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java @ 8500:992f62c457b0
-More bug fixes
author | Christos Kotselidis <christos.kotselidis@oracle.com> |
---|---|
date | Tue, 05 Mar 2013 18:53:26 +0100 |
parents | 5a98bf7d847b |
children | 39432a1cefdd |
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) 2000, 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; | |
26 | |
27 import java.io.PrintStream; | |
28 import java.net.*; | |
29 import java.rmi.*; | |
30 import sun.jvm.hotspot.debugger.*; | |
3960 | 31 import sun.jvm.hotspot.debugger.bsd.*; |
0 | 32 import sun.jvm.hotspot.debugger.proc.*; |
33 import sun.jvm.hotspot.debugger.remote.*; | |
34 import sun.jvm.hotspot.debugger.windbg.*; | |
35 import sun.jvm.hotspot.debugger.linux.*; | |
36 import sun.jvm.hotspot.memory.*; | |
37 import sun.jvm.hotspot.oops.*; | |
38 import sun.jvm.hotspot.runtime.*; | |
39 import sun.jvm.hotspot.types.*; | |
40 import sun.jvm.hotspot.utilities.*; | |
41 | |
42 /** <P> This class wraps much of the basic functionality and is the | |
43 * highest-level factory for VM data structures. It makes it simple | |
44 * to start up the debugging system. </P> | |
45 * | |
46 * <P> FIXME: especially with the addition of remote debugging, this | |
47 * has turned into a mess; needs rethinking. </P> | |
48 */ | |
49 | |
50 public class HotSpotAgent { | |
51 private JVMDebugger debugger; | |
52 private MachineDescription machDesc; | |
53 private TypeDataBase db; | |
54 | |
55 private String os; | |
56 private String cpu; | |
57 private String fileSep; | |
58 | |
59 // The system can work in several ways: | |
60 // - Attaching to local process | |
61 // - Attaching to local core file | |
62 // - Connecting to remote debug server | |
63 // - Starting debug server for process | |
64 // - Starting debug server for core file | |
65 | |
66 // These are options for the "client" side of things | |
67 private static final int PROCESS_MODE = 0; | |
68 private static final int CORE_FILE_MODE = 1; | |
69 private static final int REMOTE_MODE = 2; | |
70 private int startupMode; | |
71 | |
72 // This indicates whether we are really starting a server or not | |
73 private boolean isServer; | |
74 | |
75 // All possible required information for connecting | |
76 private int pid; | |
77 private String javaExecutableName; | |
78 private String coreFileName; | |
79 private String debugServerID; | |
80 | |
81 // All needed information for server side | |
82 private String serverID; | |
83 | |
84 private String[] jvmLibNames; | |
85 | |
86 static void showUsage() { | |
87 } | |
88 | |
89 public HotSpotAgent() { | |
90 // for non-server add shutdown hook to clean-up debugger in case | |
91 // of forced exit. For remote server, shutdown hook is added by | |
92 // DebugServer. | |
93 Runtime.getRuntime().addShutdownHook(new java.lang.Thread( | |
94 new Runnable() { | |
95 public void run() { | |
96 synchronized (HotSpotAgent.this) { | |
97 if (!isServer) { | |
98 detach(); | |
99 } | |
100 } | |
101 } | |
102 })); | |
103 } | |
104 | |
105 //-------------------------------------------------------------------------------- | |
106 // Accessors (once the system is set up) | |
107 // | |
108 | |
109 public synchronized Debugger getDebugger() { | |
110 return debugger; | |
111 } | |
112 | |
113 public synchronized TypeDataBase getTypeDataBase() { | |
114 return db; | |
115 } | |
116 | |
117 //-------------------------------------------------------------------------------- | |
118 // Client-side operations | |
119 // | |
120 | |
121 /** This attaches to a process running on the local machine. */ | |
122 public synchronized void attach(int processID) | |
123 throws DebuggerException { | |
124 if (debugger != null) { | |
125 throw new DebuggerException("Already attached"); | |
126 } | |
127 pid = processID; | |
128 startupMode = PROCESS_MODE; | |
129 isServer = false; | |
130 go(); | |
131 } | |
132 | |
133 /** This opens a core file on the local machine */ | |
134 public synchronized void attach(String javaExecutableName, String coreFileName) | |
135 throws DebuggerException { | |
136 if (debugger != null) { | |
137 throw new DebuggerException("Already attached"); | |
138 } | |
139 if ((javaExecutableName == null) || (coreFileName == null)) { | |
140 throw new DebuggerException("Both the core file name and Java executable name must be specified"); | |
141 } | |
142 this.javaExecutableName = javaExecutableName; | |
143 this.coreFileName = coreFileName; | |
144 startupMode = CORE_FILE_MODE; | |
145 isServer = false; | |
146 go(); | |
147 } | |
148 | |
149 /** This attaches to a "debug server" on a remote machine; this | |
150 remote server has already attached to a process or opened a | |
151 core file and is waiting for RMI calls on the Debugger object to | |
152 come in. */ | |
153 public synchronized void attach(String remoteServerID) | |
154 throws DebuggerException { | |
155 if (debugger != null) { | |
156 throw new DebuggerException("Already attached to a process"); | |
157 } | |
158 if (remoteServerID == null) { | |
159 throw new DebuggerException("Debug server id must be specified"); | |
160 } | |
161 | |
162 debugServerID = remoteServerID; | |
163 startupMode = REMOTE_MODE; | |
164 isServer = false; | |
165 go(); | |
166 } | |
167 | |
168 /** This should only be called by the user on the client machine, | |
169 not the server machine */ | |
170 public synchronized boolean detach() throws DebuggerException { | |
171 if (isServer) { | |
172 throw new DebuggerException("Should not call detach() for server configuration"); | |
173 } | |
174 return detachInternal(); | |
175 } | |
176 | |
177 //-------------------------------------------------------------------------------- | |
178 // Server-side operations | |
179 // | |
180 | |
181 /** This attaches to a process running on the local machine and | |
182 starts a debug server, allowing remote machines to connect and | |
183 examine this process. Uses specified name to uniquely identify a | |
184 specific debuggee on the server */ | |
185 public synchronized void startServer(int processID, String uniqueID) { | |
186 if (debugger != null) { | |
187 throw new DebuggerException("Already attached"); | |
188 } | |
189 pid = processID; | |
190 startupMode = PROCESS_MODE; | |
191 isServer = true; | |
192 serverID = uniqueID; | |
193 go(); | |
194 } | |
195 | |
196 /** This attaches to a process running on the local machine and | |
197 starts a debug server, allowing remote machines to connect and | |
198 examine this process. */ | |
199 public synchronized void startServer(int processID) | |
200 throws DebuggerException { | |
201 startServer(processID, null); | |
202 } | |
203 | |
204 /** This opens a core file on the local machine and starts a debug | |
205 server, allowing remote machines to connect and examine this | |
206 core file. Uses supplied uniqueID to uniquely identify a specific | |
207 debugee */ | |
208 public synchronized void startServer(String javaExecutableName, | |
209 String coreFileName, | |
210 String uniqueID) { | |
211 if (debugger != null) { | |
212 throw new DebuggerException("Already attached"); | |
213 } | |
214 if ((javaExecutableName == null) || (coreFileName == null)) { | |
215 throw new DebuggerException("Both the core file name and Java executable name must be specified"); | |
216 } | |
217 this.javaExecutableName = javaExecutableName; | |
218 this.coreFileName = coreFileName; | |
219 startupMode = CORE_FILE_MODE; | |
220 isServer = true; | |
221 serverID = uniqueID; | |
222 go(); | |
223 } | |
224 | |
225 /** This opens a core file on the local machine and starts a debug | |
226 server, allowing remote machines to connect and examine this | |
227 core file. */ | |
228 public synchronized void startServer(String javaExecutableName, String coreFileName) | |
229 throws DebuggerException { | |
230 startServer(javaExecutableName, coreFileName, null); | |
231 } | |
232 | |
233 /** This may only be called on the server side after startServer() | |
234 has been called */ | |
235 public synchronized boolean shutdownServer() throws DebuggerException { | |
236 if (!isServer) { | |
237 throw new DebuggerException("Should not call shutdownServer() for client configuration"); | |
238 } | |
239 return detachInternal(); | |
240 } | |
241 | |
242 | |
243 //-------------------------------------------------------------------------------- | |
244 // Internals only below this point | |
245 // | |
246 | |
247 private boolean detachInternal() { | |
248 if (debugger == null) { | |
249 return false; | |
250 } | |
251 boolean retval = true; | |
252 if (!isServer) { | |
253 VM.shutdown(); | |
254 } | |
255 // We must not call detach() if we are a client and are connected | |
256 // to a remote debugger | |
257 Debugger dbg = null; | |
258 DebuggerException ex = null; | |
259 if (isServer) { | |
260 try { | |
261 RMIHelper.unbind(serverID); | |
262 } | |
263 catch (DebuggerException de) { | |
264 ex = de; | |
265 } | |
266 dbg = debugger; | |
267 } else { | |
268 if (startupMode != REMOTE_MODE) { | |
269 dbg = debugger; | |
270 } | |
271 } | |
272 if (dbg != null) { | |
273 retval = dbg.detach(); | |
274 } | |
275 | |
276 debugger = null; | |
277 machDesc = null; | |
278 db = null; | |
279 if (ex != null) { | |
280 throw(ex); | |
281 } | |
282 return retval; | |
283 } | |
284 | |
285 private void go() { | |
286 setupDebugger(); | |
287 setupVM(); | |
288 } | |
289 | |
290 private void setupDebugger() { | |
291 if (startupMode != REMOTE_MODE) { | |
292 // | |
293 // Local mode (client attaching to local process or setting up | |
294 // server, but not client attaching to server) | |
295 // | |
296 | |
297 try { | |
298 os = PlatformInfo.getOS(); | |
299 cpu = PlatformInfo.getCPU(); | |
300 } | |
301 catch (UnsupportedPlatformException e) { | |
302 throw new DebuggerException(e); | |
303 } | |
304 fileSep = System.getProperty("file.separator"); | |
305 | |
306 if (os.equals("solaris")) { | |
307 setupDebuggerSolaris(); | |
308 } else if (os.equals("win32")) { | |
309 setupDebuggerWin32(); | |
310 } else if (os.equals("linux")) { | |
311 setupDebuggerLinux(); | |
3960 | 312 } else if (os.equals("bsd")) { |
313 setupDebuggerBsd(); | |
0 | 314 } else { |
315 // Add support for more operating systems here | |
316 throw new DebuggerException("Operating system " + os + " not yet supported"); | |
317 } | |
318 | |
319 if (isServer) { | |
320 RemoteDebuggerServer remote = null; | |
321 try { | |
322 remote = new RemoteDebuggerServer(debugger); | |
323 } | |
324 catch (RemoteException rem) { | |
325 throw new DebuggerException(rem); | |
326 } | |
327 RMIHelper.rebind(serverID, remote); | |
328 } | |
329 } else { | |
330 // | |
331 // Remote mode (client attaching to server) | |
332 // | |
333 | |
334 // Create and install a security manager | |
335 | |
336 // FIXME: currently commented out because we were having | |
337 // security problems since we're "in the sun.* hierarchy" here. | |
338 // Perhaps a permissive policy file would work around this. In | |
339 // the long run, will probably have to move into com.sun.*. | |
340 | |
341 // if (System.getSecurityManager() == null) { | |
342 // System.setSecurityManager(new RMISecurityManager()); | |
343 // } | |
344 | |
345 connectRemoteDebugger(); | |
346 } | |
347 } | |
348 | |
349 private void setupVM() { | |
350 // We need to instantiate a HotSpotTypeDataBase on both the client | |
351 // and server machine. On the server it is only currently used to | |
352 // configure the Java primitive type sizes (which we should | |
353 // consider making constant). On the client it is used to | |
354 // configure the VM. | |
355 | |
356 try { | |
357 if (os.equals("solaris")) { | |
358 db = new HotSpotTypeDataBase(machDesc, | |
359 new HotSpotSolarisVtblAccess(debugger, jvmLibNames), | |
360 debugger, jvmLibNames); | |
361 } else if (os.equals("win32")) { | |
362 db = new HotSpotTypeDataBase(machDesc, | |
363 new Win32VtblAccess(debugger, jvmLibNames), | |
364 debugger, jvmLibNames); | |
365 } else if (os.equals("linux")) { | |
366 db = new HotSpotTypeDataBase(machDesc, | |
367 new LinuxVtblAccess(debugger, jvmLibNames), | |
368 debugger, jvmLibNames); | |
3960 | 369 } else if (os.equals("bsd")) { |
370 db = new HotSpotTypeDataBase(machDesc, | |
371 new BsdVtblAccess(debugger, jvmLibNames), | |
372 debugger, jvmLibNames); | |
0 | 373 } else { |
374 throw new DebuggerException("OS \"" + os + "\" not yet supported (no VtblAccess yet)"); | |
375 } | |
376 } | |
377 catch (NoSuchSymbolException e) { | |
378 throw new DebuggerException("Doesn't appear to be a HotSpot VM (could not find symbol \"" + | |
379 e.getSymbol() + "\" in remote process)"); | |
380 } | |
381 | |
382 if (startupMode != REMOTE_MODE) { | |
383 // Configure the debugger with the primitive type sizes just obtained from the VM | |
384 debugger.configureJavaPrimitiveTypeSizes(db.getJBooleanType().getSize(), | |
385 db.getJByteType().getSize(), | |
386 db.getJCharType().getSize(), | |
387 db.getJDoubleType().getSize(), | |
388 db.getJFloatType().getSize(), | |
389 db.getJIntType().getSize(), | |
390 db.getJLongType().getSize(), | |
391 db.getJShortType().getSize()); | |
392 } | |
393 | |
394 if (!isServer) { | |
395 // Do not initialize the VM on the server (unnecessary, since it's | |
396 // instantiated on the client) | |
397 try { | |
398 VM.initialize(db, debugger); | |
399 } catch (DebuggerException e) { | |
400 throw (e); | |
401 } catch (Exception e) { | |
402 throw new DebuggerException(e); | |
403 } | |
404 } | |
405 } | |
406 | |
407 //-------------------------------------------------------------------------------- | |
408 // OS-specific debugger setup/connect routines | |
409 // | |
410 | |
411 // | |
412 // Solaris | |
413 // | |
414 | |
415 private void setupDebuggerSolaris() { | |
416 setupJVMLibNamesSolaris(); | |
3939 | 417 ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true); |
418 debugger = dbg; | |
419 attachDebugger(); | |
0 | 420 |
3939 | 421 // Set up CPU-dependent stuff |
422 if (cpu.equals("x86")) { | |
423 machDesc = new MachineDescriptionIntelX86(); | |
424 } else if (cpu.equals("sparc")) { | |
425 int addressSize = dbg.getRemoteProcessAddressSize(); | |
426 if (addressSize == -1) { | |
427 throw new DebuggerException("Error occurred while trying to determine the remote process's " + | |
428 "address size"); | |
0 | 429 } |
430 | |
3939 | 431 if (addressSize == 32) { |
432 machDesc = new MachineDescriptionSPARC32Bit(); | |
433 } else if (addressSize == 64) { | |
434 machDesc = new MachineDescriptionSPARC64Bit(); | |
0 | 435 } else { |
3939 | 436 throw new DebuggerException("Address size " + addressSize + " is not supported on SPARC"); |
0 | 437 } |
3939 | 438 } else if (cpu.equals("amd64")) { |
439 machDesc = new MachineDescriptionAMD64(); | |
440 } else { | |
441 throw new DebuggerException("Solaris only supported on sparc/sparcv9/x86/amd64"); | |
442 } | |
0 | 443 |
3939 | 444 dbg.setMachineDescription(machDesc); |
445 return; | |
0 | 446 } |
447 | |
448 private void connectRemoteDebugger() throws DebuggerException { | |
449 RemoteDebugger remote = | |
450 (RemoteDebugger) RMIHelper.lookup(debugServerID); | |
451 debugger = new RemoteDebuggerClient(remote); | |
452 machDesc = ((RemoteDebuggerClient) debugger).getMachineDescription(); | |
453 os = debugger.getOS(); | |
454 if (os.equals("solaris")) { | |
455 setupJVMLibNamesSolaris(); | |
456 } else if (os.equals("win32")) { | |
457 setupJVMLibNamesWin32(); | |
458 } else if (os.equals("linux")) { | |
459 setupJVMLibNamesLinux(); | |
3960 | 460 } else if (os.equals("bsd")) { |
461 setupJVMLibNamesBsd(); | |
0 | 462 } else { |
463 throw new RuntimeException("Unknown OS type"); | |
464 } | |
465 | |
466 cpu = debugger.getCPU(); | |
467 } | |
468 | |
469 private void setupJVMLibNamesSolaris() { | |
470 jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" }; | |
471 } | |
472 | |
473 // | |
474 // Win32 | |
475 // | |
476 | |
477 private void setupDebuggerWin32() { | |
478 setupJVMLibNamesWin32(); | |
479 | |
480 if (cpu.equals("x86")) { | |
481 machDesc = new MachineDescriptionIntelX86(); | |
482 } else if (cpu.equals("amd64")) { | |
483 machDesc = new MachineDescriptionAMD64(); | |
484 } else if (cpu.equals("ia64")) { | |
485 machDesc = new MachineDescriptionIA64(); | |
486 } else { | |
487 throw new DebuggerException("Win32 supported under x86, amd64 and ia64 only"); | |
488 } | |
489 | |
490 // Note we do not use a cache for the local debugger in server | |
491 // mode; it will be taken care of on the client side (once remote | |
492 // debugging is implemented). | |
493 | |
3939 | 494 debugger = new WindbgDebuggerLocal(machDesc, !isServer); |
0 | 495 |
496 attachDebugger(); | |
497 | |
498 // FIXME: add support for server mode | |
499 } | |
500 | |
501 private void setupJVMLibNamesWin32() { | |
502 jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" }; | |
503 } | |
504 | |
505 // | |
506 // Linux | |
507 // | |
508 | |
509 private void setupDebuggerLinux() { | |
510 setupJVMLibNamesLinux(); | |
511 | |
512 if (cpu.equals("x86")) { | |
513 machDesc = new MachineDescriptionIntelX86(); | |
514 } else if (cpu.equals("ia64")) { | |
515 machDesc = new MachineDescriptionIA64(); | |
516 } else if (cpu.equals("amd64")) { | |
517 machDesc = new MachineDescriptionAMD64(); | |
518 } else if (cpu.equals("sparc")) { | |
519 if (LinuxDebuggerLocal.getAddressSize()==8) { | |
520 machDesc = new MachineDescriptionSPARC64Bit(); | |
521 } else { | |
522 machDesc = new MachineDescriptionSPARC32Bit(); | |
523 } | |
524 } else { | |
6641
a9fed06c01d2
7154641: Servicability agent should work on platforms other than x86, sparc
bpittore
parents:
6073
diff
changeset
|
525 try { |
a9fed06c01d2
7154641: Servicability agent should work on platforms other than x86, sparc
bpittore
parents:
6073
diff
changeset
|
526 machDesc = (MachineDescription) |
a9fed06c01d2
7154641: Servicability agent should work on platforms other than x86, sparc
bpittore
parents:
6073
diff
changeset
|
527 Class.forName("sun.jvm.hotspot.debugger.MachineDescription" + |
a9fed06c01d2
7154641: Servicability agent should work on platforms other than x86, sparc
bpittore
parents:
6073
diff
changeset
|
528 cpu.toUpperCase()).newInstance(); |
a9fed06c01d2
7154641: Servicability agent should work on platforms other than x86, sparc
bpittore
parents:
6073
diff
changeset
|
529 } catch (Exception e) { |
a9fed06c01d2
7154641: Servicability agent should work on platforms other than x86, sparc
bpittore
parents:
6073
diff
changeset
|
530 throw new DebuggerException("Linux not supported on machine type " + cpu); |
a9fed06c01d2
7154641: Servicability agent should work on platforms other than x86, sparc
bpittore
parents:
6073
diff
changeset
|
531 } |
0 | 532 } |
533 | |
534 LinuxDebuggerLocal dbg = | |
535 new LinuxDebuggerLocal(machDesc, !isServer); | |
536 debugger = dbg; | |
537 | |
538 attachDebugger(); | |
539 } | |
540 | |
541 private void setupJVMLibNamesLinux() { | |
542 jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; | |
543 } | |
544 | |
3960 | 545 // |
546 // BSD | |
547 // | |
548 | |
549 private void setupDebuggerBsd() { | |
550 setupJVMLibNamesBsd(); | |
551 | |
552 if (cpu.equals("x86")) { | |
553 machDesc = new MachineDescriptionIntelX86(); | |
6073
78d2ae5ab35b
7163117: Agent can't connect to process on Mac OSX
nloodin
parents:
3960
diff
changeset
|
554 } else if (cpu.equals("amd64") || cpu.equals("x86_64")) { |
3960 | 555 machDesc = new MachineDescriptionAMD64(); |
556 } else { | |
6073
78d2ae5ab35b
7163117: Agent can't connect to process on Mac OSX
nloodin
parents:
3960
diff
changeset
|
557 throw new DebuggerException("BSD only supported on x86/x86_64. Current arch: " + cpu); |
3960 | 558 } |
559 | |
560 BsdDebuggerLocal dbg = new BsdDebuggerLocal(machDesc, !isServer); | |
561 debugger = dbg; | |
562 | |
563 attachDebugger(); | |
564 } | |
565 | |
566 private void setupJVMLibNamesBsd() { | |
567 jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" }; | |
568 } | |
569 | |
0 | 570 /** Convenience routine which should be called by per-platform |
571 debugger setup. Should not be called when startupMode is | |
572 REMOTE_MODE. */ | |
573 private void attachDebugger() { | |
574 if (startupMode == PROCESS_MODE) { | |
575 debugger.attach(pid); | |
576 } else if (startupMode == CORE_FILE_MODE) { | |
577 debugger.attach(javaExecutableName, coreFileName); | |
578 } else { | |
579 throw new DebuggerException("Should not call attach() for startupMode == " + startupMode); | |
580 } | |
581 } | |
582 } |