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 }