annotate agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java @ 3908:7588156f5cf9

7051798: SA-JDI: NPE in Frame.addressOfStackSlot(Frame.java:244) Reviewed-by: kvn
author never
date Mon, 05 Sep 2011 17:09:05 -0700
parents c18cbe5936b8
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1 /*
1552
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 0
diff changeset
2 * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
0
a61af66fc99e Initial load
duke
parents:
diff changeset
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
a61af66fc99e Initial load
duke
parents:
diff changeset
4 *
a61af66fc99e Initial load
duke
parents:
diff changeset
5 * This code is free software; you can redistribute it and/or modify it
a61af66fc99e Initial load
duke
parents:
diff changeset
6 * under the terms of the GNU General Public License version 2 only, as
a61af66fc99e Initial load
duke
parents:
diff changeset
7 * published by the Free Software Foundation.
a61af66fc99e Initial load
duke
parents:
diff changeset
8 *
a61af66fc99e Initial load
duke
parents:
diff changeset
9 * This code is distributed in the hope that it will be useful, but WITHOUT
a61af66fc99e Initial load
duke
parents:
diff changeset
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
a61af66fc99e Initial load
duke
parents:
diff changeset
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a61af66fc99e Initial load
duke
parents:
diff changeset
12 * version 2 for more details (a copy is included in the LICENSE file that
a61af66fc99e Initial load
duke
parents:
diff changeset
13 * accompanied this code).
a61af66fc99e Initial load
duke
parents:
diff changeset
14 *
a61af66fc99e Initial load
duke
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License version
a61af66fc99e Initial load
duke
parents:
diff changeset
16 * 2 along with this work; if not, write to the Free Software Foundation,
a61af66fc99e Initial load
duke
parents:
diff changeset
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
a61af66fc99e Initial load
duke
parents:
diff changeset
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
a61af66fc99e Initial load
duke
parents:
diff changeset
22 *
a61af66fc99e Initial load
duke
parents:
diff changeset
23 */
a61af66fc99e Initial load
duke
parents:
diff changeset
24
a61af66fc99e Initial load
duke
parents:
diff changeset
25 package sun.jvm.hotspot.runtime.amd64;
a61af66fc99e Initial load
duke
parents:
diff changeset
26
a61af66fc99e Initial load
duke
parents:
diff changeset
27 import sun.jvm.hotspot.debugger.*;
a61af66fc99e Initial load
duke
parents:
diff changeset
28 import sun.jvm.hotspot.debugger.amd64.*;
a61af66fc99e Initial load
duke
parents:
diff changeset
29 import sun.jvm.hotspot.code.*;
a61af66fc99e Initial load
duke
parents:
diff changeset
30 import sun.jvm.hotspot.interpreter.*;
a61af66fc99e Initial load
duke
parents:
diff changeset
31 import sun.jvm.hotspot.runtime.*;
3908
7588156f5cf9 7051798: SA-JDI: NPE in Frame.addressOfStackSlot(Frame.java:244)
never
parents: 1552
diff changeset
32 import sun.jvm.hotspot.runtime.x86.*;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
33
a61af66fc99e Initial load
duke
parents:
diff changeset
34 /** <P> Should be able to be used on all amd64 platforms we support
a61af66fc99e Initial load
duke
parents:
diff changeset
35 (Linux/amd64) to implement JavaThread's
a61af66fc99e Initial load
duke
parents:
diff changeset
36 "currentFrameGuess()" functionality. Input is an AMD64ThreadContext;
a61af66fc99e Initial load
duke
parents:
diff changeset
37 output is SP, FP, and PC for an AMD64Frame. Instantiation of the
a61af66fc99e Initial load
duke
parents:
diff changeset
38 AMD64Frame is left to the caller, since we may need to subclass
a61af66fc99e Initial load
duke
parents:
diff changeset
39 AMD64Frame to support signal handler frames on Unix platforms. </P>
a61af66fc99e Initial load
duke
parents:
diff changeset
40
a61af66fc99e Initial load
duke
parents:
diff changeset
41 <P> Algorithm is to walk up the stack within a given range (say,
a61af66fc99e Initial load
duke
parents:
diff changeset
42 512K at most) looking for a plausible PC and SP for a Java frame,
a61af66fc99e Initial load
duke
parents:
diff changeset
43 also considering those coming in from the context. If we find a PC
a61af66fc99e Initial load
duke
parents:
diff changeset
44 that belongs to the VM (i.e., in generated code like the
a61af66fc99e Initial load
duke
parents:
diff changeset
45 interpreter or CodeCache) then we try to find an associated EBP.
a61af66fc99e Initial load
duke
parents:
diff changeset
46 We repeat this until we either find a complete frame or run out of
a61af66fc99e Initial load
duke
parents:
diff changeset
47 stack to look at. </P> */
a61af66fc99e Initial load
duke
parents:
diff changeset
48
a61af66fc99e Initial load
duke
parents:
diff changeset
49 public class AMD64CurrentFrameGuess {
a61af66fc99e Initial load
duke
parents:
diff changeset
50 private AMD64ThreadContext context;
a61af66fc99e Initial load
duke
parents:
diff changeset
51 private JavaThread thread;
a61af66fc99e Initial load
duke
parents:
diff changeset
52 private Address spFound;
a61af66fc99e Initial load
duke
parents:
diff changeset
53 private Address fpFound;
a61af66fc99e Initial load
duke
parents:
diff changeset
54 private Address pcFound;
a61af66fc99e Initial load
duke
parents:
diff changeset
55
a61af66fc99e Initial load
duke
parents:
diff changeset
56 private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.amd64.AMD64Frame.DEBUG")
a61af66fc99e Initial load
duke
parents:
diff changeset
57 != null;
a61af66fc99e Initial load
duke
parents:
diff changeset
58
a61af66fc99e Initial load
duke
parents:
diff changeset
59 public AMD64CurrentFrameGuess(AMD64ThreadContext context,
a61af66fc99e Initial load
duke
parents:
diff changeset
60 JavaThread thread) {
a61af66fc99e Initial load
duke
parents:
diff changeset
61 this.context = context;
a61af66fc99e Initial load
duke
parents:
diff changeset
62 this.thread = thread;
a61af66fc99e Initial load
duke
parents:
diff changeset
63 }
a61af66fc99e Initial load
duke
parents:
diff changeset
64
a61af66fc99e Initial load
duke
parents:
diff changeset
65 /** Returns false if not able to find a frame within a reasonable range. */
a61af66fc99e Initial load
duke
parents:
diff changeset
66 public boolean run(long regionInBytesToSearch) {
a61af66fc99e Initial load
duke
parents:
diff changeset
67 Address sp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
a61af66fc99e Initial load
duke
parents:
diff changeset
68 Address pc = context.getRegisterAsAddress(AMD64ThreadContext.RIP);
a61af66fc99e Initial load
duke
parents:
diff changeset
69 Address fp = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
a61af66fc99e Initial load
duke
parents:
diff changeset
70 if (sp == null) {
a61af66fc99e Initial load
duke
parents:
diff changeset
71 // Bail out if no last java frame either
a61af66fc99e Initial load
duke
parents:
diff changeset
72 if (thread.getLastJavaSP() != null) {
a61af66fc99e Initial load
duke
parents:
diff changeset
73 setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null);
a61af66fc99e Initial load
duke
parents:
diff changeset
74 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
75 }
a61af66fc99e Initial load
duke
parents:
diff changeset
76 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
77 }
a61af66fc99e Initial load
duke
parents:
diff changeset
78 Address end = sp.addOffsetTo(regionInBytesToSearch);
a61af66fc99e Initial load
duke
parents:
diff changeset
79 VM vm = VM.getVM();
a61af66fc99e Initial load
duke
parents:
diff changeset
80
a61af66fc99e Initial load
duke
parents:
diff changeset
81 setValues(null, null, null); // Assume we're not going to find anything
a61af66fc99e Initial load
duke
parents:
diff changeset
82
a61af66fc99e Initial load
duke
parents:
diff changeset
83 if (vm.isJavaPCDbg(pc)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
84 if (vm.isClientCompiler()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
85 // If the topmost frame is a Java frame, we are (pretty much)
a61af66fc99e Initial load
duke
parents:
diff changeset
86 // guaranteed to have a viable EBP. We should be more robust
a61af66fc99e Initial load
duke
parents:
diff changeset
87 // than this (we have the potential for losing entire threads'
a61af66fc99e Initial load
duke
parents:
diff changeset
88 // stack traces) but need to see how much work we really have
a61af66fc99e Initial load
duke
parents:
diff changeset
89 // to do here. Searching the stack for an (SP, FP) pair is
a61af66fc99e Initial load
duke
parents:
diff changeset
90 // hard since it's easy to misinterpret inter-frame stack
a61af66fc99e Initial load
duke
parents:
diff changeset
91 // pointers as base-of-frame pointers; we also don't know the
a61af66fc99e Initial load
duke
parents:
diff changeset
92 // sizes of C1 frames (not registered in the nmethod) so can't
a61af66fc99e Initial load
duke
parents:
diff changeset
93 // derive them from ESP.
a61af66fc99e Initial load
duke
parents:
diff changeset
94
a61af66fc99e Initial load
duke
parents:
diff changeset
95 setValues(sp, fp, pc);
a61af66fc99e Initial load
duke
parents:
diff changeset
96 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
97 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
98 if (vm.getInterpreter().contains(pc)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
99 if (DEBUG) {
a61af66fc99e Initial load
duke
parents:
diff changeset
100 System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " +
a61af66fc99e Initial load
duke
parents:
diff changeset
101 sp + ", fp = " + fp + ", pc = " + pc);
a61af66fc99e Initial load
duke
parents:
diff changeset
102 }
a61af66fc99e Initial load
duke
parents:
diff changeset
103 setValues(sp, fp, pc);
a61af66fc99e Initial load
duke
parents:
diff changeset
104 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
105 }
a61af66fc99e Initial load
duke
parents:
diff changeset
106
a61af66fc99e Initial load
duke
parents:
diff changeset
107 // For the server compiler, EBP is not guaranteed to be valid
a61af66fc99e Initial load
duke
parents:
diff changeset
108 // for compiled code. In addition, an earlier attempt at a
a61af66fc99e Initial load
duke
parents:
diff changeset
109 // non-searching algorithm (see below) failed because the
a61af66fc99e Initial load
duke
parents:
diff changeset
110 // stack pointer from the thread context was pointing
a61af66fc99e Initial load
duke
parents:
diff changeset
111 // (considerably) beyond the ostensible end of the stack, into
a61af66fc99e Initial load
duke
parents:
diff changeset
112 // garbage; walking from the topmost frame back caused a crash.
a61af66fc99e Initial load
duke
parents:
diff changeset
113 //
a61af66fc99e Initial load
duke
parents:
diff changeset
114 // This algorithm takes the current PC as a given and tries to
a61af66fc99e Initial load
duke
parents:
diff changeset
115 // find the correct corresponding SP by walking up the stack
a61af66fc99e Initial load
duke
parents:
diff changeset
116 // and repeatedly performing stackwalks (very inefficient).
a61af66fc99e Initial load
duke
parents:
diff changeset
117 //
a61af66fc99e Initial load
duke
parents:
diff changeset
118 // FIXME: there is something wrong with stackwalking across
a61af66fc99e Initial load
duke
parents:
diff changeset
119 // adapter frames...this is likely to be the root cause of the
a61af66fc99e Initial load
duke
parents:
diff changeset
120 // failure with the simpler algorithm below.
a61af66fc99e Initial load
duke
parents:
diff changeset
121
a61af66fc99e Initial load
duke
parents:
diff changeset
122 for (long offset = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
123 offset < regionInBytesToSearch;
a61af66fc99e Initial load
duke
parents:
diff changeset
124 offset += vm.getAddressSize()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
125 try {
a61af66fc99e Initial load
duke
parents:
diff changeset
126 Address curSP = sp.addOffsetTo(offset);
3908
7588156f5cf9 7051798: SA-JDI: NPE in Frame.addressOfStackSlot(Frame.java:244)
never
parents: 1552
diff changeset
127 Frame frame = new X86Frame(curSP, null, pc);
0
a61af66fc99e Initial load
duke
parents:
diff changeset
128 RegisterMap map = thread.newRegisterMap(false);
a61af66fc99e Initial load
duke
parents:
diff changeset
129 while (frame != null) {
a61af66fc99e Initial load
duke
parents:
diff changeset
130 if (frame.isEntryFrame() && frame.entryFrameIsFirst()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
131 // We were able to traverse all the way to the
a61af66fc99e Initial load
duke
parents:
diff changeset
132 // bottommost Java frame.
a61af66fc99e Initial load
duke
parents:
diff changeset
133 // This sp looks good. Keep it.
a61af66fc99e Initial load
duke
parents:
diff changeset
134 if (DEBUG) {
a61af66fc99e Initial load
duke
parents:
diff changeset
135 System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc);
a61af66fc99e Initial load
duke
parents:
diff changeset
136 }
a61af66fc99e Initial load
duke
parents:
diff changeset
137 setValues(curSP, null, pc);
a61af66fc99e Initial load
duke
parents:
diff changeset
138 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
139 }
a61af66fc99e Initial load
duke
parents:
diff changeset
140 frame = frame.sender(map);
a61af66fc99e Initial load
duke
parents:
diff changeset
141 }
a61af66fc99e Initial load
duke
parents:
diff changeset
142 } catch (Exception e) {
a61af66fc99e Initial load
duke
parents:
diff changeset
143 if (DEBUG) {
a61af66fc99e Initial load
duke
parents:
diff changeset
144 System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset);
a61af66fc99e Initial load
duke
parents:
diff changeset
145 }
a61af66fc99e Initial load
duke
parents:
diff changeset
146 // Bad SP. Try another.
a61af66fc99e Initial load
duke
parents:
diff changeset
147 }
a61af66fc99e Initial load
duke
parents:
diff changeset
148 }
a61af66fc99e Initial load
duke
parents:
diff changeset
149
a61af66fc99e Initial load
duke
parents:
diff changeset
150 // Were not able to find a plausible SP to go with this PC.
a61af66fc99e Initial load
duke
parents:
diff changeset
151 // Bail out.
a61af66fc99e Initial load
duke
parents:
diff changeset
152 return false;
a61af66fc99e Initial load
duke
parents:
diff changeset
153
a61af66fc99e Initial load
duke
parents:
diff changeset
154 /*
a61af66fc99e Initial load
duke
parents:
diff changeset
155 // Original algorithm which does not work because SP was
a61af66fc99e Initial load
duke
parents:
diff changeset
156 // pointing beyond where it should have:
a61af66fc99e Initial load
duke
parents:
diff changeset
157
a61af66fc99e Initial load
duke
parents:
diff changeset
158 // For the server compiler, EBP is not guaranteed to be valid
a61af66fc99e Initial load
duke
parents:
diff changeset
159 // for compiled code. We see whether the PC is in the
a61af66fc99e Initial load
duke
parents:
diff changeset
160 // interpreter and take care of that, otherwise we run code
a61af66fc99e Initial load
duke
parents:
diff changeset
161 // (unfortunately) duplicated from AMD64Frame.senderForCompiledFrame.
a61af66fc99e Initial load
duke
parents:
diff changeset
162
a61af66fc99e Initial load
duke
parents:
diff changeset
163 CodeCache cc = vm.getCodeCache();
a61af66fc99e Initial load
duke
parents:
diff changeset
164 if (cc.contains(pc)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
165 CodeBlob cb = cc.findBlob(pc);
a61af66fc99e Initial load
duke
parents:
diff changeset
166
a61af66fc99e Initial load
duke
parents:
diff changeset
167 // See if we can derive a frame pointer from SP and PC
a61af66fc99e Initial load
duke
parents:
diff changeset
168 // NOTE: This is the code duplicated from AMD64Frame
a61af66fc99e Initial load
duke
parents:
diff changeset
169 Address saved_fp = null;
a61af66fc99e Initial load
duke
parents:
diff changeset
170 int llink_offset = cb.getLinkOffset();
a61af66fc99e Initial load
duke
parents:
diff changeset
171 if (llink_offset >= 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
172 // Restore base-pointer, since next frame might be an interpreter frame.
a61af66fc99e Initial load
duke
parents:
diff changeset
173 Address fp_addr = sp.addOffsetTo(VM.getVM().getAddressSize() * llink_offset);
a61af66fc99e Initial load
duke
parents:
diff changeset
174 saved_fp = fp_addr.getAddressAt(0);
a61af66fc99e Initial load
duke
parents:
diff changeset
175 }
a61af66fc99e Initial load
duke
parents:
diff changeset
176
a61af66fc99e Initial load
duke
parents:
diff changeset
177 setValues(sp, saved_fp, pc);
a61af66fc99e Initial load
duke
parents:
diff changeset
178 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
179 }
a61af66fc99e Initial load
duke
parents:
diff changeset
180 */
a61af66fc99e Initial load
duke
parents:
diff changeset
181 }
a61af66fc99e Initial load
duke
parents:
diff changeset
182 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
183 // If the current program counter was not known to us as a Java
a61af66fc99e Initial load
duke
parents:
diff changeset
184 // PC, we currently assume that we are in the run-time system
a61af66fc99e Initial load
duke
parents:
diff changeset
185 // and attempt to look to thread-local storage for saved ESP and
a61af66fc99e Initial load
duke
parents:
diff changeset
186 // EBP. Note that if these are null (because we were, in fact,
a61af66fc99e Initial load
duke
parents:
diff changeset
187 // in Java code, i.e., vtable stubs or similar, and the SA
a61af66fc99e Initial load
duke
parents:
diff changeset
188 // didn't have enough insight into the target VM to understand
a61af66fc99e Initial load
duke
parents:
diff changeset
189 // that) then we are going to lose the entire stack trace for
a61af66fc99e Initial load
duke
parents:
diff changeset
190 // the thread, which is sub-optimal. FIXME.
a61af66fc99e Initial load
duke
parents:
diff changeset
191
a61af66fc99e Initial load
duke
parents:
diff changeset
192 if (DEBUG) {
a61af66fc99e Initial load
duke
parents:
diff changeset
193 System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " +
a61af66fc99e Initial load
duke
parents:
diff changeset
194 thread.getLastJavaSP() + ", fp = " + thread.getLastJavaFP());
a61af66fc99e Initial load
duke
parents:
diff changeset
195 }
a61af66fc99e Initial load
duke
parents:
diff changeset
196 if (thread.getLastJavaSP() == null) {
a61af66fc99e Initial load
duke
parents:
diff changeset
197 return false; // No known Java frames on stack
a61af66fc99e Initial load
duke
parents:
diff changeset
198 }
a61af66fc99e Initial load
duke
parents:
diff changeset
199 setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null);
a61af66fc99e Initial load
duke
parents:
diff changeset
200 return true;
a61af66fc99e Initial load
duke
parents:
diff changeset
201 }
a61af66fc99e Initial load
duke
parents:
diff changeset
202 }
a61af66fc99e Initial load
duke
parents:
diff changeset
203
a61af66fc99e Initial load
duke
parents:
diff changeset
204 public Address getSP() { return spFound; }
a61af66fc99e Initial load
duke
parents:
diff changeset
205 public Address getFP() { return fpFound; }
a61af66fc99e Initial load
duke
parents:
diff changeset
206 /** May be null if getting values from thread-local storage; take
a61af66fc99e Initial load
duke
parents:
diff changeset
207 care to call the correct AMD64Frame constructor to recover this if
a61af66fc99e Initial load
duke
parents:
diff changeset
208 necessary */
a61af66fc99e Initial load
duke
parents:
diff changeset
209 public Address getPC() { return pcFound; }
a61af66fc99e Initial load
duke
parents:
diff changeset
210
a61af66fc99e Initial load
duke
parents:
diff changeset
211 private void setValues(Address sp, Address fp, Address pc) {
a61af66fc99e Initial load
duke
parents:
diff changeset
212 spFound = sp;
a61af66fc99e Initial load
duke
parents:
diff changeset
213 fpFound = fp;
a61af66fc99e Initial load
duke
parents:
diff changeset
214 pcFound = pc;
a61af66fc99e Initial load
duke
parents:
diff changeset
215 }
a61af66fc99e Initial load
duke
parents:
diff changeset
216 }