1 /*
2 * Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved.
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 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 package sun.jvm.hotspot.runtime.x86;
26
27 import sun.jvm.hotspot.debugger;
28 import sun.jvm.hotspot.debugger.x86;
29 import sun.jvm.hotspot.code;
30 import sun.jvm.hotspot.interpreter;
31 import sun.jvm.hotspot.runtime;
32
33 /** <P> Should be able to be used on all x86 platforms we support
34 (Win32, Solaris/x86, and soon Linux) to implement JavaThread's
35 "currentFrameGuess()" functionality. Input is an X86ThreadContext;
36 output is SP, FP, and PC for an X86Frame. Instantiation of the
37 X86Frame is left to the caller, since we may need to subclass
38 X86Frame to support signal handler frames on Unix platforms. </P>
39
40 <P> Algorithm is to walk up the stack within a given range (say,
41 512K at most) looking for a plausible PC and SP for a Java frame,
42 also considering those coming in from the context. If we find a PC
43 that belongs to the VM (i.e., in generated code like the
44 interpreter or CodeCache) then we try to find an associated EBP.
45 We repeat this until we either find a complete frame or run out of
46 stack to look at. </P> */
47
48 public class X86CurrentFrameGuess {
49 private X86ThreadContext context;
50 private JavaThread thread;
51 private Address spFound;
52 private Address fpFound;
53 private Address pcFound;
54
55 private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.x86.X86Frame.DEBUG")
56 != null;
57
58 public X86CurrentFrameGuess(X86ThreadContext context,
59 JavaThread thread) {
60 this.context = context;
61 this.thread = thread;
62 }
63
64 /** Returns false if not able to find a frame within a reasonable range. */
65 public boolean run(long regionInBytesToSearch) {
66 Address sp = context.getRegisterAsAddress(X86ThreadContext.SP);
67 Address pc = context.getRegisterAsAddress(X86ThreadContext.PC);
68 Address fp = context.getRegisterAsAddress(X86ThreadContext.FP);
69 if (sp == null) {
70 // Bail out if no last java frame eithe
71 if (thread.getLastJavaSP() != null) {
72 setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null);
73 return true;
74 }
75 // Bail out
76 return false;
77 }
78 Address end = sp.addOffsetTo(regionInBytesToSearch);
79 VM vm = VM.getVM();
80
81 setValues(null, null, null); // Assume we're not going to find anything
82
83 if (vm.isJavaPCDbg(pc)) {
84 if (vm.isClientCompiler()) {
85 // If the topmost frame is a Java frame, we are (pretty much)
86 // guaranteed to have a viable EBP. We should be more robust
87 // than this (we have the potential for losing entire threads'
88 // stack traces) but need to see how much work we really have
89 // to do here. Searching the stack for an (SP, FP) pair is
90 // hard since it's easy to misinterpret inter-frame stack
91 // pointers as base-of-frame pointers; we also don't know the
92 // sizes of C1 frames (not registered in the nmethod) so can't
93 // derive them from ESP.
94
95 setValues(sp, fp, pc);
96 return true;
97 } else {
98 if (vm.getInterpreter().contains(pc)) {
99 if (DEBUG) {
100 System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " +
101 sp + ", fp = " + fp + ", pc = " + pc);
102 }
103 setValues(sp, fp, pc);
104 return true;
105 }
106
107 // For the server compiler, EBP is not guaranteed to be valid
108 // for compiled code. In addition, an earlier attempt at a
109 // non-searching algorithm (see below) failed because the
110 // stack pointer from the thread context was pointing
111 // (considerably) beyond the ostensible end of the stack, into
112 // garbage; walking from the topmost frame back caused a crash.
113 //
114 // This algorithm takes the current PC as a given and tries to
115 // find the correct corresponding SP by walking up the stack
116 // and repeatedly performing stackwalks (very inefficient).
117 //
118 // FIXME: there is something wrong with stackwalking across
119 // adapter frames...this is likely to be the root cause of the
120 // failure with the simpler algorithm below.
121
122 for (long offset = 0;
123 offset < regionInBytesToSearch;
124 offset += vm.getAddressSize()) {
125 try {
126 Address curSP = sp.addOffsetTo(offset);
127 Frame frame = new X86Frame(curSP, null, pc);
128 RegisterMap map = thread.newRegisterMap(false);
129 while (frame != null) {
130 if (frame.isEntryFrame() && frame.entryFrameIsFirst()) {
131 // We were able to traverse all the way to the
132 // bottommost Java frame.
133 // This sp looks good. Keep it.
134 if (DEBUG) {
135 System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc);
136 }
137 setValues(curSP, null, pc);
138 return true;
139 }
140 frame = frame.sender(map);
141 }
142 } catch (Exception e) {
143 if (DEBUG) {
144 System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset);
145 }
146 // Bad SP. Try another.
147 }
148 }
149
150 // Were not able to find a plausible SP to go with this PC.
151 // Bail out.
152 return false;
153
154 /*
155 // Original algorithm which does not work because SP was
156 // pointing beyond where it should have:
157
158 // For the server compiler, EBP is not guaranteed to be valid
159 // for compiled code. We see whether the PC is in the
160 // interpreter and take care of that, otherwise we run code
161 // (unfortunately) duplicated from X86Frame.senderForCompiledFrame.
162
163 CodeCache cc = vm.getCodeCache();
164 if (cc.contains(pc)) {
165 CodeBlob cb = cc.findBlob(pc);
166
167 // See if we can derive a frame pointer from SP and PC
168 // NOTE: This is the code duplicated from X86Frame
169 Address saved_fp = null;
170 int llink_offset = cb.getLinkOffset();
171 if (llink_offset >= 0) {
172 // Restore base-pointer, since next frame might be an interpreter frame.
173 Address fp_addr = sp.addOffsetTo(VM.getVM().getAddressSize() * llink_offset);
174 saved_fp = fp_addr.getAddressAt(0);
175 }
176
177 setValues(sp, saved_fp, pc);
178 return true;
179 }
180 */
181 }
182 } else {
183 // If the current program counter was not known to us as a Java
184 // PC, we currently assume that we are in the run-time system
185 // and attempt to look to thread-local storage for saved ESP and
186 // EBP. Note that if these are null (because we were, in fact,
187 // in Java code, i.e., vtable stubs or similar, and the SA
188 // didn't have enough insight into the target VM to understand
189 // that) then we are going to lose the entire stack trace for
190 // the thread, which is sub-optimal. FIXME.
191
192 if (DEBUG) {
193 System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " +
194 thread.getLastJavaSP() + ", fp = " + thread.getLastJavaFP());
195 }
196 if (thread.getLastJavaSP() == null) {
197 return false; // No known Java frames on stack
198 }
199 setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null);
200 return true;
201 }
202 }
203
204 public Address getSP() { return spFound; }
205 public Address getFP() { return fpFound; }
206 /** May be null if getting values from thread-local storage; take
207 care to call the correct X86Frame constructor to recover this if
208 necessary */
209 public Address getPC() { return pcFound; }
210
211 private void setValues(Address sp, Address fp, Address pc) {
212 spFound = sp;
213 fpFound = fp;
214 pcFound = pc;
215 }
216 }