Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/livejvm/ServiceabilityAgentJVMDIModule.java @ 1917:f42a2f0c16bb
6996563: 6984311 changes forgot to update vmStructs.cpp for new field _operands
Summary: Add missing line to vmStructs. Also fix bug with class dumper.
Reviewed-by: twisti, kvn
author | jrose |
---|---|
date | Fri, 05 Nov 2010 12:18:30 -0700 |
parents | c18cbe5936b8 |
children |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2002, 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.livejvm; | |
26 | |
27 import sun.jvm.hotspot.debugger.*; | |
28 import sun.jvm.hotspot.oops.*; | |
29 import sun.jvm.hotspot.runtime.*; | |
30 | |
31 /** Provides Java programming language-level interaction with a live | |
32 Java HotSpot VM via the use of the SA's JVMDI module. This is an | |
33 experimental mechanism. The BugSpot debugger should be converted | |
34 to use the JVMDI/JDWP-based JDI implementation for live process | |
35 interaction once the JDI binding for the SA is complete. */ | |
36 | |
37 public class ServiceabilityAgentJVMDIModule { | |
38 private Debugger dbg; | |
39 private String[] saLibNames; | |
40 private String saLibName; | |
41 private boolean attached; | |
42 | |
43 private boolean suspended; | |
44 | |
45 private static final int JVMDI_EVENT_BREAKPOINT = 2; | |
46 private static final int JVMDI_EVENT_EXCEPTION = 4; | |
47 | |
48 private static long timeoutMillis = 3000; | |
49 | |
50 // Values in target process | |
51 // Events sent from VM to SA | |
52 private CIntegerAccessor saAttached; | |
53 private CIntegerAccessor saEventPending; | |
54 private CIntegerAccessor saEventKind; | |
55 // Exception events | |
56 private JNIHandleAccessor saExceptionThread; | |
57 private JNIHandleAccessor saExceptionClass; | |
58 private JNIid saExceptionMethod; | |
59 private CIntegerAccessor saExceptionLocation; | |
60 private JNIHandleAccessor saExceptionException; | |
61 private JNIHandleAccessor saExceptionCatchClass; | |
62 private JNIid saExceptionCatchMethod; | |
63 private CIntegerAccessor saExceptionCatchLocation; | |
64 // Breakpoint events | |
65 private JNIHandleAccessor saBreakpointThread; | |
66 private JNIHandleAccessor saBreakpointClass; | |
67 private JNIid saBreakpointMethod; | |
68 private CIntegerAccessor saBreakpointLocation; | |
69 // Commands sent by the SA to the VM | |
70 private int SA_CMD_SUSPEND_ALL; | |
71 private int SA_CMD_RESUME_ALL; | |
72 private int SA_CMD_TOGGLE_BREAKPOINT; | |
73 private int SA_CMD_BUF_SIZE; | |
74 private CIntegerAccessor saCmdPending; | |
75 private CIntegerAccessor saCmdType; | |
76 private CIntegerAccessor saCmdResult; | |
77 private CStringAccessor saCmdResultErrMsg; | |
78 // Toggle breakpoint command arguments | |
79 private CStringAccessor saCmdBkptSrcFileName; | |
80 private CStringAccessor saCmdBkptPkgName; | |
81 private CIntegerAccessor saCmdBkptLineNumber; | |
82 private CIntegerAccessor saCmdBkptResWasError; | |
83 private CIntegerAccessor saCmdBkptResLineNumber; | |
84 private CIntegerAccessor saCmdBkptResBCI; | |
85 private CIntegerAccessor saCmdBkptResWasSet; | |
86 private CStringAccessor saCmdBkptResMethodName; | |
87 private CStringAccessor saCmdBkptResMethodSig; | |
88 | |
89 public ServiceabilityAgentJVMDIModule(Debugger dbg, String[] saLibNames) { | |
90 this.dbg = dbg; | |
91 this.saLibNames = saLibNames; | |
92 } | |
93 | |
94 /** Indicates whether a call to attach() should complete without an | |
95 exception. */ | |
96 public boolean canAttach() { | |
97 return setupLookup("SA_CMD_SUSPEND_ALL"); | |
98 } | |
99 | |
100 /** Attempt to initiate a connection with the JVMDI module in the | |
101 target VM. */ | |
102 public void attach() throws DebuggerException { | |
103 if (!canAttach()) { | |
104 throw new DebuggerException("Unable to initiate symbol lookup in SA's JVMDI module"); | |
105 } | |
106 | |
107 if (attached) { | |
108 throw new DebuggerException("Already attached"); | |
109 } | |
110 | |
111 // Attempt to look up well-known symbols in the target VM. | |
112 SA_CMD_SUSPEND_ALL = lookupConstInt("SA_CMD_SUSPEND_ALL"); | |
113 SA_CMD_RESUME_ALL = lookupConstInt("SA_CMD_RESUME_ALL"); | |
114 SA_CMD_TOGGLE_BREAKPOINT = lookupConstInt("SA_CMD_TOGGLE_BREAKPOINT"); | |
115 SA_CMD_BUF_SIZE = lookupConstInt("SA_CMD_BUF_SIZE"); | |
116 | |
117 saAttached = lookupCInt("saAttached"); | |
118 saEventPending = lookupCInt("saEventPending"); | |
119 saEventKind = lookupCInt("saEventKind"); | |
120 saCmdPending = lookupCInt("saCmdPending"); | |
121 saCmdType = lookupCInt("saCmdType"); | |
122 saCmdResult = lookupCInt("saCmdResult"); | |
123 saCmdResultErrMsg = lookupCString("saCmdResultErrMsg", SA_CMD_BUF_SIZE); | |
124 // Toggling of breakpoints | |
125 saCmdBkptSrcFileName = lookupCString("saCmdBkptSrcFileName", SA_CMD_BUF_SIZE); | |
126 saCmdBkptPkgName = lookupCString("saCmdBkptPkgName", SA_CMD_BUF_SIZE); | |
127 saCmdBkptLineNumber = lookupCInt("saCmdBkptLineNumber"); | |
128 saCmdBkptResWasError = lookupCInt("saCmdBkptResWasError"); | |
129 saCmdBkptResLineNumber = lookupCInt("saCmdBkptResLineNumber"); | |
130 saCmdBkptResBCI = lookupCInt("saCmdBkptResBCI"); | |
131 saCmdBkptResWasSet = lookupCInt("saCmdBkptResWasSet"); | |
132 saCmdBkptResMethodName = lookupCString("saCmdBkptResMethodName", SA_CMD_BUF_SIZE); | |
133 saCmdBkptResMethodSig = lookupCString("saCmdBkptResMethodSig", SA_CMD_BUF_SIZE); | |
134 | |
135 // Check for existence of symbols needed later | |
136 // FIXME: should probably cache these since we can't support the | |
137 // -Xrun module or the VM getting unloaded anyway | |
138 lookup("saExceptionThread"); | |
139 lookup("saExceptionClass"); | |
140 lookup("saExceptionMethod"); | |
141 lookup("saExceptionLocation"); | |
142 lookup("saExceptionException"); | |
143 lookup("saExceptionCatchClass"); | |
144 lookup("saExceptionCatchMethod"); | |
145 lookup("saExceptionCatchLocation"); | |
146 lookup("saBreakpointThread"); | |
147 lookup("saBreakpointClass"); | |
148 lookup("saBreakpointMethod"); | |
149 lookup("saBreakpointLocation"); | |
150 | |
151 saAttached.setValue(1); | |
152 attached = true; | |
153 } | |
154 | |
155 public void detach() { | |
156 saAttached.setValue(0); | |
157 attached = false; | |
158 saLibName = null; | |
159 } | |
160 | |
161 /** Set the timeout value (in milliseconds) for the VM to reply to | |
162 commands. Once this timeout has elapsed, the VM is assumed to | |
163 have disconnected. Defaults to 3000 milliseconds (3 seconds). */ | |
164 public void setCommandTimeout(long millis) { | |
165 timeoutMillis = millis; | |
166 } | |
167 | |
168 /** Get the timeout value (in milliseconds) for the VM to reply to | |
169 commands. Once this timeout has elapsed, the VM is assumed to | |
170 have disconnected. Defaults to 3000 milliseconds (3 seconds). */ | |
171 public long getCommandTimeout() { | |
172 return timeoutMillis; | |
173 } | |
174 | |
175 /** Indicates whether a Java debug event is pending */ | |
176 public boolean eventPending() { | |
177 return (saEventPending.getValue() != 0); | |
178 } | |
179 | |
180 /** Poll for event; returns null if none pending. */ | |
181 public Event eventPoll() { | |
182 if (saEventPending.getValue() == 0) { | |
183 return null; | |
184 } | |
185 | |
186 int kind = (int) saEventKind.getValue(); | |
187 switch (kind) { | |
188 case JVMDI_EVENT_EXCEPTION: { | |
189 JNIHandleAccessor thread = lookupJNIHandle("saExceptionThread"); | |
190 JNIHandleAccessor clazz = lookupJNIHandle("saExceptionClass"); | |
191 JNIid method = lookupJNIid("saExceptionMethod"); | |
192 CIntegerAccessor location = lookupCInt("saExceptionLocation"); | |
193 JNIHandleAccessor exception = lookupJNIHandle("saExceptionException"); | |
194 JNIHandleAccessor catchClass = lookupJNIHandle("saExceptionCatchClass"); | |
195 JNIid catchMethod = lookupJNIid("saExceptionCatchMethod"); | |
196 CIntegerAccessor catchLocation = lookupCInt("saExceptionCatchLocation"); | |
197 return new ExceptionEvent(thread.getValue(), clazz.getValue(), method, | |
198 (int) location.getValue(), exception.getValue(), | |
199 catchClass.getValue(), catchMethod, (int) catchLocation.getValue()); | |
200 } | |
201 | |
202 case JVMDI_EVENT_BREAKPOINT: { | |
203 JNIHandleAccessor thread = lookupJNIHandle("saBreakpointThread"); | |
204 JNIHandleAccessor clazz = lookupJNIHandle("saBreakpointClass"); | |
205 JNIid method = lookupJNIid("saBreakpointMethod"); | |
206 CIntegerAccessor location = lookupCInt("saBreakpointLocation"); | |
207 return new BreakpointEvent(thread.getValue(), clazz.getValue(), | |
208 method, (int) location.getValue()); | |
209 } | |
210 | |
211 default: | |
212 throw new DebuggerException("Unsupported event type " + kind); | |
213 } | |
214 } | |
215 | |
216 /** Continue past current event */ | |
217 public void eventContinue() { | |
218 saEventPending.setValue(0); | |
219 } | |
220 | |
221 /** Suspend all Java threads in the target VM. Throws | |
222 DebuggerException if the VM disconnected. */ | |
223 public void suspend() { | |
224 saCmdType.setValue(SA_CMD_SUSPEND_ALL); | |
225 saCmdPending.setValue(1); | |
226 waitForCommandCompletion(); | |
227 suspended = true; | |
228 } | |
229 | |
230 /** Resume all Java threads in the target VM. Throws | |
231 DebuggerException if the VM disconnected. */ | |
232 public void resume() { | |
233 saCmdType.setValue(SA_CMD_RESUME_ALL); | |
234 saCmdPending.setValue(1); | |
235 waitForCommandCompletion(); | |
236 suspended = false; | |
237 } | |
238 | |
239 /** Indicates whether all Java threads have been suspended via this | |
240 interface. */ | |
241 public boolean isSuspended() { | |
242 return suspended; | |
243 } | |
244 | |
245 /** Information about toggling of breakpoints */ | |
246 public static class BreakpointToggleResult { | |
247 private boolean success; | |
248 private String errMsg; | |
249 private int lineNumber; | |
250 private int bci; | |
251 private boolean wasSet; | |
252 private String methodName; | |
253 private String methodSig; | |
254 | |
255 /** Success constructor */ | |
256 public BreakpointToggleResult(int lineNumber, int bci, boolean wasSet, | |
257 String methodName, String methodSig) { | |
258 this.lineNumber = lineNumber; | |
259 this.bci = bci; | |
260 this.wasSet = wasSet; | |
261 this.methodName = methodName; | |
262 this.methodSig = methodSig; | |
263 success = true; | |
264 } | |
265 | |
266 /** Failure constructor */ | |
267 public BreakpointToggleResult(String errMsg) { | |
268 this.errMsg = errMsg; | |
269 success = false; | |
270 } | |
271 | |
272 /** Indicates whether this represents a successful return or not */ | |
273 public boolean getSuccess() { return success; } | |
274 | |
275 /** Valid only if getSuccess() returns false */ | |
276 public String getErrMsg() { return errMsg; } | |
277 | |
278 /** Line number at which breakpoint toggle occurred; valid only if | |
279 getSuccess() returns true. */ | |
280 public int getLineNumber() { return lineNumber; } | |
281 | |
282 /** BCI at which breakpoint toggle occurred; valid only if | |
283 getSuccess() returns true. */ | |
284 public int getBCI() { return bci; } | |
285 | |
286 /** Indicates whether the breakpoint toggle was the set of a | |
287 breakpoint or not; valid only if getSuccess() returns true. */ | |
288 public boolean getWasSet() { return wasSet; } | |
289 | |
290 /** Method name in which the breakpoint toggle occurred; valid | |
291 only if getSuccess() returns true. */ | |
292 public String getMethodName() { return methodName; } | |
293 | |
294 /** Method signature in which the breakpoint toggle occurred; | |
295 valid only if getSuccess() returns true. */ | |
296 public String getMethodSignature() { return methodSig; } | |
297 } | |
298 | |
299 /** Toggle a breakpoint. Throws DebuggerException if a real error | |
300 occurred; otherwise returns non-null BreakpointToggleResult. The | |
301 work of scanning the loaded classes is done in the target VM | |
302 because it turns out to be significantly faster than scanning | |
303 through the system dictionary from the SA, and interactivity | |
304 when setting breakpoints is important. */ | |
305 public BreakpointToggleResult toggleBreakpoint(String srcFileName, | |
306 String pkgName, | |
307 int lineNo) { | |
308 saCmdBkptSrcFileName.setValue(srcFileName); | |
309 saCmdBkptPkgName.setValue(pkgName); | |
310 saCmdBkptLineNumber.setValue(lineNo); | |
311 saCmdType.setValue(SA_CMD_TOGGLE_BREAKPOINT); | |
312 saCmdPending.setValue(1); | |
313 if (waitForCommandCompletion(true)) { | |
314 return new BreakpointToggleResult((int) saCmdBkptResLineNumber.getValue(), | |
315 (int) saCmdBkptResBCI.getValue(), | |
316 (saCmdBkptResWasSet.getValue() != 0), | |
317 saCmdBkptResMethodName.getValue(), | |
318 saCmdBkptResMethodSig.getValue()); | |
319 } else { | |
320 return new BreakpointToggleResult(saCmdResultErrMsg.getValue()); | |
321 } | |
322 } | |
323 | |
324 | |
325 //---------------------------------------------------------------------- | |
326 // Internals only below this point | |
327 // | |
328 | |
329 private CIntegerAccessor lookupCInt(String symbolName) { | |
330 return new CIntegerAccessor(lookup(symbolName), 4, false); | |
331 } | |
332 | |
333 private CStringAccessor lookupCString(String symbolName, int bufLen) { | |
334 return new CStringAccessor(lookup(symbolName), bufLen); | |
335 } | |
336 | |
337 private JNIHandleAccessor lookupJNIHandle(String symbolName) { | |
338 return new JNIHandleAccessor(lookup(symbolName), VM.getVM().getObjectHeap()); | |
339 } | |
340 | |
341 private JNIid lookupJNIid(String symbolName) { | |
342 Address idAddr = lookup(symbolName).getAddressAt(0); | |
343 if (idAddr == null) { | |
344 return null; | |
345 } | |
346 return new JNIid(idAddr, VM.getVM().getObjectHeap()); | |
347 } | |
348 | |
349 private int lookupConstInt(String symbolName) { | |
350 Address addr = lookup(symbolName); | |
351 return (int) addr.getCIntegerAt(0, 4, false); | |
352 } | |
353 | |
354 private boolean setupLookup(String symbolName) { | |
355 if (saLibName == null) { | |
356 for (int i = 0; i < saLibNames.length; i++) { | |
357 Address addr = dbg.lookup(saLibNames[i], symbolName); | |
358 if (addr != null) { | |
359 saLibName = saLibNames[i]; | |
360 return true; | |
361 } | |
362 } | |
363 return false; | |
364 } | |
365 return true; | |
366 } | |
367 | |
368 private Address lookup(String symbolName) { | |
369 if (saLibName == null) { | |
370 for (int i = 0; i < saLibNames.length; i++) { | |
371 Address addr = dbg.lookup(saLibNames[i], symbolName); | |
372 if (addr != null) { | |
373 saLibName = saLibNames[i]; | |
374 return addr; | |
375 } | |
376 } | |
377 throw new DebuggerException("Unable to find symbol " + symbolName + " in any of the known names for the SA"); | |
378 } | |
379 | |
380 Address addr = dbg.lookup(saLibName, symbolName); | |
381 if (addr == null) { | |
382 throw new DebuggerException("Unable to find symbol " + symbolName + " in " + saLibName); | |
383 } | |
384 return addr; | |
385 } | |
386 | |
387 private void waitForCommandCompletion() { | |
388 waitForCommandCompletion(false); | |
389 } | |
390 | |
391 /** Returns true if command succeeded, false if not */ | |
392 private boolean waitForCommandCompletion(boolean forBreakpoint) { | |
393 long start = System.currentTimeMillis(); | |
394 long cur = start; | |
395 while ((saCmdPending.getValue() != 0) && | |
396 (cur - start < timeoutMillis)) { | |
397 try { | |
398 java.lang.Thread.currentThread().sleep(10); | |
399 } catch (InterruptedException e) { | |
400 } | |
401 cur = System.currentTimeMillis(); | |
402 } | |
403 if (saCmdPending.getValue() != 0) { | |
404 detach(); | |
405 throw new DebuggerException("VM appears to have died"); | |
406 } | |
407 boolean succeeded = saCmdResult.getValue() == 0; | |
408 if (!succeeded && | |
409 (!forBreakpoint || saCmdBkptResWasError.getValue() != 0)) { | |
410 String err = saCmdResultErrMsg.getValue(); | |
411 throw new DebuggerException("Error executing JVMDI command: " + err); | |
412 } | |
413 return succeeded; | |
414 } | |
415 } |