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 boolean isLockOwned(Address a) {
398     Address stackBase = getStackBase();
399     Address stackLimit = stackBase.addOffsetTo(-getStackSize());
400 
401     return stackBase.greaterThan(a) && stackLimit.lessThanOrEqual(a);
402 
403     // FIXME: should traverse MonitorArray/MonitorChunks as in VM
404   }
405 
406   public Oop getCurrentParkBlocker() {
407     Oop threadObj = getThreadObj();
408     if (threadObj != null) {
409       try {
410         return OopUtilities.threadOopGetParkBlocker(threadObj);
411       } catch (Exception e) {
412         System.out.println("Could not get current park blocker: " + e);
413       }
414     }
415     return null;
416   }
417 
418   public JNIHandleBlock activeHandles() {
419     Address a = activeHandlesField.getAddress(addr);
420     if (a == null) {
421       return null;
422     }
423     return new JNIHandleBlock(a);
424   }
425 
426   public void printInfoOn(PrintStream tty) {
427 
428     tty.println("State: " + getThreadState().toString());
429     // Attempt to figure out the addresses covered by Java frames.
430     // NOTE: we should make this a method and let the Stackwalk panel use the result too.
431     //
432     sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess();
433     if (tmpFrame != null ) {
434       Address sp = tmpFrame.getSP();
435       Address maxSP = sp;
436       Address minSP = sp;
437       RegisterMap tmpMap = newRegisterMap(false);
438       while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
439           tmpFrame = tmpFrame.sender(tmpMap);
440           if (tmpFrame != null) {
441             sp = tmpFrame.getSP();
442             maxSP = AddressOps.max(maxSP, sp);
443             minSP = AddressOps.min(minSP, sp);
444           }
445       }
446       tty.println("Stack in use by Java: " + minSP + " .. " + maxSP);
447     } else {
448       tty.println("No Java frames present");
449     }
450     tty.println("Base of Stack: " + getStackBase());
451     tty.println("Last_Java_SP: " + getLastJavaSP());
452     tty.println("Last_Java_FP: " + getLastJavaFP());
453     tty.println("Last_Java_PC: " + getLastJavaPC());
454     // More stuff like saved_execption_pc, safepoint_state, ...
455     access.printInfoOn(addr, tty);
456 
457   }
458 
459   ///////////////////////////////
460   //                           //
461   // FIXME: add more accessors //
462   //                           //
463   ///////////////////////////////
464 
465   //--------------------------------------------------------------------------------
466   // Internals only below this point
467   //
468 
469   private Frame cookLastFrame(Frame fr) {
470     if (fr == null) {
471       return null;
472     }
473 
474     Address pc        = fr.getPC();
475 
476     if (Assert.ASSERTS_ENABLED) {
477       if (pc == null) {
478         Assert.that(VM.getVM().isDebugging(), "must have PC");
479       }
480     }
481     return fr;
482   }
483 
484   public Address lastSPDbg() {
485     return access.getLastSP(addr);
486   }
487 
488   // Print the contents of all registers in the thread's context
489   public void printThreadContextOn(PrintStream out, boolean verbose){
490     ThreadContext tc = getThreadProxy().getContext();
491     for (int r = 0; r < tc.getNumRegisters(); r++) {
492       Address regAddr = tc.getRegisterAsAddress(r);
493       System.out.format("%s: %s", tc.getRegisterName(r), regAddr);
494       if (regAddr == null) {
495         System.out.println();
496       } else {
497         PointerLocation l = PointerFinder.find(regAddr);
498         if (l.isUnknown()) {
499           System.out.println();
500         } else {
501           System.out.print(": ");
502           l.printOn(System.out, false, verbose);
503         }
504       }
505     }
506   }
507 
508   public void printThreadInfoOn(PrintStream out){
509       String threadName = "<unknown>";
510       boolean daemon = false;
511       int priority = java.lang.Thread.MIN_PRIORITY - 1;
512       String statusName = "<unknown>";
513 
514       Oop threadOop = this.getThreadObj();
515       if (threadOop == null) {
516           System.out.println("Could not get the java Thread object. Thread info will be limited.");
517       } else {
518           // Some of these accesses can throw an Exception if we are in the
519           // middle of a GC, so be cautious.
520           try {
521               threadName = this.getThreadName();
522           } catch (Exception e) {}
523           try {
524               // These all rely on the FieldHolder object, so if one fails, they all fail.
525               daemon = OopUtilities.threadOopGetDaemon(threadOop);
526               priority = OopUtilities.threadOopGetPriority(threadOop);
527               statusName = OopUtilities.threadOopGetThreadStatusName(threadOop);
528           } catch (Exception e) {}
529           out.print("\"");
530           out.print(threadName);
531           out.print("\" #");
532           out.print(OopUtilities.threadOopGetTID(threadOop));
533           if (daemon) {
534               out.print(" daemon");
535           }
536           out.print(" prio=");
537           if (priority == java.lang.Thread.MIN_PRIORITY - 1) {
538               out.print("<unknown>");
539           } else {
540               out.print(priority);
541           }
542       }
543       out.print(" tid=");
544       out.print(this.getAddress());
545       out.print(" nid=");
546       out.print(String.format("%d ", this.getOSThread().threadId()));
547       out.print(getOSThread().getThreadState().getPrintVal());
548       out.print(" [");
549       if (this.getLastJavaSP() == null) {
550           out.print(String.format(ADDRESS_FORMAT, 0L));
551       } else {
552           out.print(this.getLastJavaSP().andWithMask(~0xFFF));
553       }
554       out.println("]");
555       if (threadOop != null) {
556           out.print("   java.lang.Thread.State: ");
557           out.println(statusName);
558       }
559       out.print("   JavaThread state: _thread_");
560       out.println(this.getThreadState().toString().toLowerCase());
561   }
562 }