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

Save This Page
Home » openjdk-7 » sun.jvm » hotspot » runtime » amd64 » [javadoc | source]