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 }