1 /*
  2  * Copyright (c) 2000, 2022, 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;
 26 
 27 import java.io.*;
 28 import java.util.*;
 29 import sun.jvm.hotspot.debugger.*;
 30 import sun.jvm.hotspot.oops.*;
 31 import sun.jvm.hotspot.types.*;
 32 import sun.jvm.hotspot.utilities.*;
 33 import sun.jvm.hotspot.utilities.Observable;
 34 import sun.jvm.hotspot.utilities.Observer;
 35 
 36 /** This is an abstract class because there are certain OS- and
 37     CPU-specific operations (like the setting and getting of the last
 38     Java frame pointer) which need to be factored out. These
 39     operations are implemented by, for example,
 40     SolarisSPARCJavaThread, and the concrete subclasses are
 41     instantiated by the JavaThreadFactory in the Threads class. */
 42 
 43 public class JavaThread extends Thread {
 44   private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.JavaThread.DEBUG") != null;
 45 
 46   private static long          threadObjFieldOffset;
 47   private static AddressField  anchorField;
 48   private static AddressField  lastJavaSPField;
 49   private static AddressField  lastJavaPCField;
 50   private static CIntegerField threadStateField;
 51   private static AddressField  osThreadField;
 52   private static AddressField  stackBaseField;
 53   private static CIntegerField stackSizeField;
 54   private static CIntegerField terminatedField;
 55   private static AddressField activeHandlesField;
 56 
 57   private static JavaThreadPDAccess access;
 58 
 59   // JavaThreadStates read from underlying process
 60   private static int           UNINITIALIZED;
 61   private static int           NEW;
 62   private static int           NEW_TRANS;
 63   private static int           IN_NATIVE;
 64   private static int           IN_NATIVE_TRANS;
 65   private static int           IN_VM;
 66   private static int           IN_VM_TRANS;
 67   private static int           IN_JAVA;
 68   private static int           IN_JAVA_TRANS;
 69   private static int           BLOCKED;
 70   private static int           BLOCKED_TRANS;
 71 
 72   private static int           NOT_TERMINATED;
 73   private static int           EXITING;
 74 
 75   private static final String  ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x" : "0x%08x";
 76 
 77   static {
 78     VM.registerVMInitializedObserver(new Observer() {
 79         public void update(Observable o, Object data) {
 80           initialize(VM.getVM().getTypeDataBase());
 81         }
 82       });
 83   }
 84 
 85   private static synchronized void initialize(TypeDataBase db) {
 86     Type type = db.lookupType("JavaThread");
 87     Type anchorType = db.lookupType("JavaFrameAnchor");
 88 
 89     threadObjFieldOffset = type.getField("_threadObj").getOffset();
 90 
 91     anchorField       = type.getAddressField("_anchor");
 92     lastJavaSPField   = anchorType.getAddressField("_last_Java_sp");
 93     lastJavaPCField   = anchorType.getAddressField("_last_Java_pc");
 94     threadStateField  = type.getCIntegerField("_thread_state");
 95     osThreadField     = type.getAddressField("_osthread");
 96     stackBaseField    = type.getAddressField("_stack_base");
 97     stackSizeField    = type.getCIntegerField("_stack_size");
 98     terminatedField   = type.getCIntegerField("_terminated");
 99     activeHandlesField = type.getAddressField("_active_handles");
100 
101     UNINITIALIZED     = db.lookupIntConstant("_thread_uninitialized").intValue();
102     NEW               = db.lookupIntConstant("_thread_new").intValue();
103     NEW_TRANS         = db.lookupIntConstant("_thread_new_trans").intValue();
104     IN_NATIVE         = db.lookupIntConstant("_thread_in_native").intValue();
105     IN_NATIVE_TRANS   = db.lookupIntConstant("_thread_in_native_trans").intValue();
106     IN_VM             = db.lookupIntConstant("_thread_in_vm").intValue();
107     IN_VM_TRANS       = db.lookupIntConstant("_thread_in_vm_trans").intValue();
108     IN_JAVA           = db.lookupIntConstant("_thread_in_Java").intValue();
109     IN_JAVA_TRANS     = db.lookupIntConstant("_thread_in_Java_trans").intValue();
110     BLOCKED           = db.lookupIntConstant("_thread_blocked").intValue();
111     BLOCKED_TRANS     = db.lookupIntConstant("_thread_blocked_trans").intValue();
112 
113     NOT_TERMINATED    = db.lookupIntConstant("JavaThread::_not_terminated").intValue();
114     EXITING           = db.lookupIntConstant("JavaThread::_thread_exiting").intValue();
115 
116   }
117 
118   public JavaThread(Address addr) {
119     super(addr);
120   }
121 
122   void setThreadPDAccess(JavaThreadPDAccess access) {
123     this.access = access;
124   }
125 
126   /** NOTE: for convenience, this differs in definition from the underlying VM.
127       Only "pure" JavaThreads return true; CompilerThreads,
128       JVMDIDebuggerThreads return false.
129       FIXME:
130       consider encapsulating platform-specific functionality in an
131       object instead of using inheritance (which is the primary reason
132       we can't traverse CompilerThreads, etc; didn't want to have, for
133       example, "SolarisSPARCCompilerThread".) */
134   public boolean isJavaThread() { return true; }
135 
136   public boolean isExiting () {
137       return (getTerminated() == EXITING) || isTerminated();
138   }
139 
140   public boolean isTerminated() {
141       return (getTerminated() != NOT_TERMINATED) && (getTerminated() != EXITING);
142   }
143 
144   public static AddressField getAnchorField() { return anchorField; }
145 
146   /** Get the last Java stack pointer */
147   public Address getLastJavaSP() {
148     Address sp = lastJavaSPField.getValue(addr.addOffsetTo(anchorField.getOffset()));
149     return sp;
150   }
151 
152   public Address getLastJavaPC() {
153     Address pc = lastJavaPCField.getValue(addr.addOffsetTo(anchorField.getOffset()));
154     return pc;
155   }
156 
157   /** Abstract accessor to last Java frame pointer, implemented by
158       OS/CPU-specific JavaThread implementation. May return null if
159       there is no frame pointer or if it is not necessary on this
160       platform. */
161   public Address getLastJavaFP(){
162         return access.getLastJavaFP(addr);
163   }
164 
165   /** Abstract accessor to last Java pc, implemented by
166       OS/CPU-specific JavaThread implementation. May return null if
167       there is no frame pointer or if it is not necessary on this
168       platform. */
169 
170   /*
171   public Address getLastJavaPC(){
172         return access.getLastJavaPC(addr);
173   }
174   */
175 
176   // FIXME: not yet implementable
177   //  public abstract void    setLastJavaFP(Address fp);
178 
179   /** A stack pointer older than any java frame stack pointer. Only
180       needed on some platforms; for example, see
181       thread_solaris_sparc.hpp. */
182   public Address getBaseOfStackPointer(){
183         return access.getBaseOfStackPointer(addr);
184   }
185   // FIXME: not yet implementable
186   //  public abstract void    setBaseOfStackPointer(Address fp);
187 
188   /** Tells whether the last Java frame is set */
189   public boolean hasLastJavaFrame() {
190     return (getLastJavaSP() != null);
191   }
192 
193   /** Accessing frames */
194   public Frame getLastFrame() {
195     // FIXME: would need to implement runtime routine
196     // "cacheStatePD(boolean)" for reflective system to be able to
197     // flush register windows on SPARC
198     return cookLastFrame(getLastFramePD());
199   }
200 
201   /** Internal routine implemented by platform-dependent subclasses */
202   protected Frame getLastFramePD(){
203         return access.getLastFramePD(this, addr);
204   }
205 
206   /** Accessing frames. Returns the last Java VFrame or null if none
207       was present. (NOTE that this is mostly unusable in a debugging
208       system; see getLastJavaVFrameDbg, below, which provides very
209       different functionality.) */
210   public JavaVFrame getLastJavaVFrame(RegisterMap regMap) {
211     if (Assert.ASSERTS_ENABLED) {
212       Assert.that(regMap != null, "a map must be given");
213     }
214     Frame f = getLastFrame();
215     if (f == null) {
216       return null;
217     }
218     for (VFrame vf = VFrame.newVFrame(f, regMap, this); vf != null; vf = vf.sender()) {
219       if (vf.isJavaFrame()) {
220         return (JavaVFrame) vf;
221       }
222     }
223     return null;
224   }
225 
226   /** This should only be used by a debugger. Uses the current frame
227       guess to attempt to get the topmost JavaVFrame.
228       (getLastJavaVFrame, as a port of the VM's routine, assumes the
229       VM is at a safepoint.) */
230   public JavaVFrame getLastJavaVFrameDbg() {
231     RegisterMap regMap = newRegisterMap(true);
232     sun.jvm.hotspot.runtime.Frame f = getCurrentFrameGuess();
233     if (f == null) return null;
234     boolean imprecise = true;
235     if (f.isInterpretedFrame() && !f.isInterpretedFrameValid()) {
236        if (DEBUG) {
237          System.out.println("Correcting for invalid interpreter frame");
238        }
239        f = f.sender(regMap);
240        imprecise = false;
241     }
242     VFrame vf = VFrame.newVFrame(f, regMap, this, true, imprecise);
243     if (vf == null) {
244       if (DEBUG) {
245         System.out.println(" (Unable to create vframe for topmost frame guess)");
246       }
247       return null;
248     }
249     return vf.isJavaFrame() ? (JavaVFrame)vf : vf.javaSender();
250   }
251 
252   /** In this system, a JavaThread is the top-level factory for a
253       RegisterMap, since the JavaThread implementation is already
254       platform-specific and RegisterMap is also necessarily
255       platform-specific. The updateMap argument indicates whether the
256       register map needs to be updated, for example during stack
257       traversal -- see frame.hpp. */
258   public RegisterMap newRegisterMap(boolean updateMap){
259         return access.newRegisterMap(this, updateMap);
260   }
261 
262   /** This is only designed to be used by the debugging system.
263       Returns a "best guess" of the topmost frame on the stack. This
264       guess should be as "raw" as possible. For example, if the
265       topmost frame is an interpreter frame (the return PC is in the
266       interpreter) but is not a valid frame (i.e., the BCI has not yet
267       been set up) this should still return the topmost frame and not
268       the sender. Validity checks are done at higher levels. */
269   public  Frame getCurrentFrameGuess(){
270         return access.getCurrentFrameGuess(this, addr);
271   }
272 
273   /** Also only intended for use by the debugging system. Provides the
274       same effect of OSThread::print(); that is, prints a value which
275       allows the user to intuitively understand which native OS thread
276       maps to this Java thread. Does not print a newline or leading or
277       trailing spaces. */
278   public  void printThreadIDOn(PrintStream tty) {
279         access.printThreadIDOn(addr,tty);
280   }
281 
282   public void printThreadID() {
283     printThreadIDOn(System.out);
284   }
285 
286   public ThreadProxy getThreadProxy() {
287     return access.getThreadProxy(addr);
288   }
289 
290   //
291   // Safepoint support
292   //
293 
294   public JavaThreadState getThreadState() {
295     int val = (int) threadStateField.getValue(addr);
296     if (val == UNINITIALIZED) {
297       return JavaThreadState.UNINITIALIZED;
298     } else if (val == NEW) {
299       return JavaThreadState.NEW;
300     } else if (val == NEW_TRANS) {
301       return JavaThreadState.NEW_TRANS;
302     } else if (val == IN_NATIVE) {
303       return JavaThreadState.IN_NATIVE;
304     } else if (val == IN_NATIVE_TRANS) {
305       return JavaThreadState.IN_NATIVE_TRANS;
306     } else if (val == IN_VM) {
307       return JavaThreadState.IN_VM;
308     } else if (val == IN_VM_TRANS) {
309       return JavaThreadState.IN_VM_TRANS;
310     } else if (val == IN_JAVA) {
311       return JavaThreadState.IN_JAVA;
312     } else if (val == IN_JAVA_TRANS) {
313       return JavaThreadState.IN_JAVA_TRANS;
314     } else if (val == BLOCKED) {
315       return JavaThreadState.BLOCKED;
316     } else if (val == BLOCKED_TRANS) {
317       return JavaThreadState.BLOCKED_TRANS;
318     } else {
319       throw new RuntimeException("Illegal thread state " + val);
320     }
321   }
322   // FIXME: not yet implementable
323   // public void setThreadState(JavaThreadState s);
324 
325   //
326   // Miscellaneous operations
327   //
328 
329   public OSThread getOSThread() {
330     return VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr));
331   }
332 
333   public Address getStackBase() {
334     return stackBaseField.getValue(addr);
335   }
336 
337   public long getStackBaseValue() {
338     return VM.getVM().getAddressValue(getStackBase());
339   }
340 
341   public long getStackSize() {
342     return stackSizeField.getValue(addr);
343   }
344 
345   public int getTerminated() {
346       return (int) terminatedField.getValue(addr);
347   }
348 
349   /** Gets the Java-side thread object for this JavaThread */
350   public Oop getThreadObj() {
351     Oop obj = null;
352     try {
353       Address addr = getAddress().addOffsetTo(threadObjFieldOffset);
354       VMOopHandle vmOopHandle = VMObjectFactory.newObject(VMOopHandle.class, addr);
355       obj = vmOopHandle.resolve();
356     } catch (Exception e) {
357       System.out.println("WARNING: could not get Thread object: " + e);
358     }
359     return obj;
360   }
361 
362   /** Get the Java-side name of this thread */
363   public String getThreadName() {
364     Oop threadObj = getThreadObj();
365     if (threadObj == null) {
366         return "<null>";
367     }
368     return OopUtilities.threadOopGetName(threadObj);
369   }
370 
371   //
372   // Oop traversal
373   //
374 
375   public void oopsDo(AddressVisitor oopVisitor) {
376     super.oopsDo(oopVisitor);
377 
378     // FIXME: add in the rest of the routine from the VM
379 
380     // Traverse the execution stack
381     for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) {
382       fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap());
383     }
384   }
385 
386   public boolean isInStack(Address a) {
387     if (Assert.ASSERTS_ENABLED) {
388       Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system");
389     }
390     Address sp      = lastSPDbg();
391     Address stackBase = getStackBase();
392     // Be robust
393     if (sp == null) return false;
394     return stackBase.greaterThan(a) && sp.lessThanOrEqual(a);
395   }
396 
397   public Oop getCurrentParkBlocker() {
398     Oop threadObj = getThreadObj();
399     if (threadObj != null) {
400       try {
401         return OopUtilities.threadOopGetParkBlocker(threadObj);
402       } catch (Exception e) {
403         System.out.println("Could not get current park blocker: " + e);
404       }
405     }
406     return null;
407   }
408 
409   public JNIHandleBlock activeHandles() {
410     Address a = activeHandlesField.getAddress(addr);
411     if (a == null) {
412       return null;
413     }
414     return new JNIHandleBlock(a);
415   }
416 
417   public void printInfoOn(PrintStream tty) {
418 
419     tty.println("State: " + getThreadState().toString());
420     // Attempt to figure out the addresses covered by Java frames.
421     // NOTE: we should make this a method and let the Stackwalk panel use the result too.
422     //
423     sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess();
424     if (tmpFrame != null ) {
425       Address sp = tmpFrame.getSP();
426       Address maxSP = sp;
427       Address minSP = sp;
428       RegisterMap tmpMap = newRegisterMap(false);
429       while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
430           tmpFrame = tmpFrame.sender(tmpMap);
431           if (tmpFrame != null) {
432             sp = tmpFrame.getSP();
433             maxSP = AddressOps.max(maxSP, sp);
434             minSP = AddressOps.min(minSP, sp);
435           }
436       }
437       tty.println("Stack in use by Java: " + minSP + " .. " + maxSP);
438     } else {
439       tty.println("No Java frames present");
440     }
441     tty.println("Base of Stack: " + getStackBase());
442     tty.println("Last_Java_SP: " + getLastJavaSP());
443     tty.println("Last_Java_FP: " + getLastJavaFP());
444     tty.println("Last_Java_PC: " + getLastJavaPC());
445     // More stuff like saved_execption_pc, safepoint_state, ...
446     access.printInfoOn(addr, tty);
447 
448   }
449 
450   ///////////////////////////////
451   //                           //
452   // FIXME: add more accessors //
453   //                           //
454   ///////////////////////////////
455 
456   //--------------------------------------------------------------------------------
457   // Internals only below this point
458   //
459 
460   private Frame cookLastFrame(Frame fr) {
461     if (fr == null) {
462       return null;
463     }
464 
465     Address pc        = fr.getPC();
466 
467     if (Assert.ASSERTS_ENABLED) {
468       if (pc == null) {
469         Assert.that(VM.getVM().isDebugging(), "must have PC");
470       }
471     }
472     return fr;
473   }
474 
475   public Address lastSPDbg() {
476     return access.getLastSP(addr);
477   }
478 
479   // Print the contents of all registers in the thread's context
480   public void printThreadContextOn(PrintStream out, boolean verbose){
481     ThreadContext tc = getThreadProxy().getContext();
482     for (int r = 0; r < tc.getNumRegisters(); r++) {
483       Address regAddr = tc.getRegisterAsAddress(r);
484       System.out.format("%s: %s", tc.getRegisterName(r), regAddr);
485       if (regAddr == null) {
486         System.out.println();
487       } else {
488         PointerLocation l = PointerFinder.find(regAddr);
489         if (l.isUnknown()) {
490           System.out.println();
491         } else {
492           System.out.print(": ");
493           l.printOn(System.out, false, verbose);
494         }
495       }
496     }
497   }
498 
499   public void printThreadInfoOn(PrintStream out){
500       String threadName = "<unknown>";
501       boolean daemon = false;
502       int priority = java.lang.Thread.MIN_PRIORITY - 1;
503       String statusName = "<unknown>";
504 
505       Oop threadOop = this.getThreadObj();
506       if (threadOop == null) {
507           System.out.println("Could not get the java Thread object. Thread info will be limited.");
508       } else {
509           // Some of these accesses can throw an Exception if we are in the
510           // middle of a GC, so be cautious.
511           try {
512               threadName = this.getThreadName();
513           } catch (Exception e) {}
514           try {
515               // These all rely on the FieldHolder object, so if one fails, they all fail.
516               daemon = OopUtilities.threadOopGetDaemon(threadOop);
517               priority = OopUtilities.threadOopGetPriority(threadOop);
518               statusName = OopUtilities.threadOopGetThreadStatusName(threadOop);
519           } catch (Exception e) {}
520           out.print("\"");
521           out.print(threadName);
522           out.print("\" #");
523           out.print(OopUtilities.threadOopGetTID(threadOop));
524           if (daemon) {
525               out.print(" daemon");
526           }
527           out.print(" prio=");
528           if (priority == java.lang.Thread.MIN_PRIORITY - 1) {
529               out.print("<unknown>");
530           } else {
531               out.print(priority);
532           }
533       }
534       out.print(" tid=");
535       out.print(this.getAddress());
536       out.print(" nid=");
537       out.print(String.format("%d ", this.getOSThread().threadId()));
538       out.print(getOSThread().getThreadState().getPrintVal());
539       out.print(" [");
540       if (this.getLastJavaSP() == null) {
541           out.print(String.format(ADDRESS_FORMAT, 0L));
542       } else {
543           out.print(this.getLastJavaSP().andWithMask(~0xFFF));
544       }
545       out.println("]");
546       if (threadOop != null) {
547           out.print("   java.lang.Thread.State: ");
548           out.println(statusName);
549       }
550       out.print("   JavaThread state: _thread_");
551       out.println(this.getThreadState().toString().toLowerCase());
552   }
553 }