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