1 /* 2 * Copyright (c) 1997, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 /* 28 * The Original Code is HAT. The Initial Developer of the 29 * Original Code is Bill Foote, with contributions from others 30 * at JavaSoft/Sun. 31 */ 32 33 package jdk.test.lib.hprof.parser; 34 35 import java.io.*; 36 import java.util.Date; 37 import java.util.Hashtable; 38 import java.util.Map; 39 import jdk.test.lib.hprof.model.ArrayTypeCodes; 40 import jdk.test.lib.hprof.model.*; 41 42 /** 43 * Object that's used to read a hprof file. 44 * 45 * @author Bill Foote 46 */ 47 48 public class HprofReader extends Reader /* imports */ implements ArrayTypeCodes { 49 50 final static int MAGIC_NUMBER = 0x4a415641; 51 // That's "JAVA", the first part of "JAVA PROFILE ..." 52 private final static String[] VERSIONS = { 53 " PROFILE 1.0\0", 54 " PROFILE 1.0.1\0", 55 " PROFILE 1.0.2\0", 56 }; 57 58 private final static int VERSION_JDK12BETA3 = 0; 59 private final static int VERSION_JDK12BETA4 = 1; 60 private final static int VERSION_JDK6 = 2; 61 // These version numbers are indices into VERSIONS. The instance data 62 // member version is set to one of these, and it drives decisions when 63 // reading the file. 64 // 65 // Version 1.0.1 added HPROF_GC_PRIM_ARRAY_DUMP, which requires no 66 // version-sensitive parsing. 67 // 68 // Version 1.0.1 changed the type of a constant pool entry from a signature 69 // to a typecode. 70 // 71 // Version 1.0.2 added HPROF_HEAP_DUMP_SEGMENT and HPROF_HEAP_DUMP_END 72 // to allow a large heap to be dumped as a sequence of heap dump segments. 73 // 74 // The HPROF agent in J2SE 1.2 through to 5.0 generate a version 1.0.1 75 // file. In Java SE 6.0 the version is either 1.0.1 or 1.0.2 depending on 76 // the size of the heap (normally it will be 1.0.1 but for multi-GB 77 // heaps the heap dump will not fit in a HPROF_HEAP_DUMP record so the 78 // dump is generated as version 1.0.2). 79 80 // 81 // Record types: 82 // 83 static final int HPROF_UTF8 = 0x01; 84 static final int HPROF_LOAD_CLASS = 0x02; 85 static final int HPROF_UNLOAD_CLASS = 0x03; 86 static final int HPROF_FRAME = 0x04; 87 static final int HPROF_TRACE = 0x05; 88 static final int HPROF_ALLOC_SITES = 0x06; 89 static final int HPROF_HEAP_SUMMARY = 0x07; 90 91 static final int HPROF_START_THREAD = 0x0a; 92 static final int HPROF_END_THREAD = 0x0b; 93 94 static final int HPROF_HEAP_DUMP = 0x0c; 95 96 static final int HPROF_CPU_SAMPLES = 0x0d; 97 static final int HPROF_CONTROL_SETTINGS = 0x0e; 98 static final int HPROF_LOCKSTATS_WAIT_TIME = 0x10; 99 static final int HPROF_LOCKSTATS_HOLD_TIME = 0x11; 100 101 static final int HPROF_GC_ROOT_UNKNOWN = 0xff; 102 static final int HPROF_GC_ROOT_JNI_GLOBAL = 0x01; 103 static final int HPROF_GC_ROOT_JNI_LOCAL = 0x02; 104 static final int HPROF_GC_ROOT_JAVA_FRAME = 0x03; 105 static final int HPROF_GC_ROOT_NATIVE_STACK = 0x04; 106 static final int HPROF_GC_ROOT_STICKY_CLASS = 0x05; 107 static final int HPROF_GC_ROOT_THREAD_BLOCK = 0x06; 108 static final int HPROF_GC_ROOT_MONITOR_USED = 0x07; 109 static final int HPROF_GC_ROOT_THREAD_OBJ = 0x08; 110 111 static final int HPROF_GC_CLASS_DUMP = 0x20; 112 static final int HPROF_GC_INSTANCE_DUMP = 0x21; 113 static final int HPROF_GC_OBJ_ARRAY_DUMP = 0x22; 114 static final int HPROF_GC_PRIM_ARRAY_DUMP = 0x23; 115 116 static final int HPROF_HEAP_DUMP_SEGMENT = 0x1c; 117 static final int HPROF_HEAP_DUMP_END = 0x2c; 118 119 private final static int T_CLASS = 2; 120 121 private int version; // The version of .hprof being read 122 123 private int debugLevel; 124 private long currPos; // Current position in the file 125 126 private int dumpsToSkip; 127 private boolean callStack; // If true, read the call stack of objects 128 129 private int identifierSize; // Size, in bytes, of identifiers. 130 private Hashtable<Long, String> names; 131 132 // Hashtable<Integer, ThreadObject>, used to map the thread sequence number 133 // (aka "serial number") to the thread object ID for 134 // HPROF_GC_ROOT_THREAD_OBJ. ThreadObject is a trivial inner class, 135 // at the end of this file. 136 private Hashtable<Integer, ThreadObject> threadObjects; 137 138 // Hashtable<Long, String>, maps class object ID to class name 139 // (with / converted to .) 140 private Hashtable<Long, String> classNameFromObjectID; 141 142 // Hashtable<Integer, Integer>, maps class serial # to class object ID 143 private Hashtable<Integer, String> classNameFromSerialNo; 144 145 // Hashtable<Long, StackFrame> maps stack frame ID to StackFrame. 146 // Null if we're not tracking them. 147 private Hashtable<Long, StackFrame> stackFrames; 148 149 // Hashtable<Integer, StackTrace> maps stack frame ID to StackTrace 150 // Null if we're not tracking them. 151 private Hashtable<Integer, StackTrace> stackTraces; 152 153 private Snapshot snapshot; 154 155 public static boolean verifyMagicNumber(int numberRead) { 156 return (numberRead == MAGIC_NUMBER); 157 } 158 159 public HprofReader(String fileName, PositionDataInputStream in, 160 int dumpNumber, boolean callStack, int debugLevel) 161 throws IOException { 162 super(in); 163 RandomAccessFile file = new RandomAccessFile(fileName, "r"); 164 this.snapshot = new Snapshot(MappedReadBuffer.create(file)); 165 this.dumpsToSkip = dumpNumber - 1; 166 this.callStack = callStack; 167 this.debugLevel = debugLevel; 168 names = new Hashtable<Long, String>(); 169 threadObjects = new Hashtable<Integer, ThreadObject>(43); 170 classNameFromObjectID = new Hashtable<Long, String>(); 171 if (callStack) { 172 stackFrames = new Hashtable<Long, StackFrame>(43); 173 stackTraces = new Hashtable<Integer, StackTrace>(43); 174 classNameFromSerialNo = new Hashtable<Integer, String>(); 175 } 176 } 177 178 public Snapshot read() throws IOException { 179 currPos = 4; // 4 because of the magic number 180 version = readVersionHeader(); 181 identifierSize = in.readInt(); 182 snapshot.setIdentifierSize(identifierSize); 183 if (version >= VERSION_JDK12BETA4) { 184 snapshot.setNewStyleArrayClass(true); 185 } else { 186 snapshot.setNewStyleArrayClass(false); 187 } 188 189 currPos += 4; 190 if (identifierSize != 4 && identifierSize != 8) { 191 throw new IOException("I'm sorry, but I can't deal with an identifier size of " + identifierSize + ". I can only deal with 4 or 8."); 192 } 193 System.out.println("Dump file created " + (new Date(in.readLong()))); 194 currPos += 8; 195 196 for (;;) { 197 int type; 198 try { 199 type = in.readUnsignedByte(); 200 } catch (EOFException ignored) { 201 break; 202 } 203 in.readInt(); // Timestamp of this record 204 // Length of record: readInt() will return negative value for record 205 // length >2GB. so store 32bit value in long to keep it unsigned. 206 long length = in.readInt() & 0xffffffffL; 207 if (debugLevel > 0) { 208 System.out.println("Read record type " + type 209 + ", length " + length 210 + " at position " + toHex(currPos)); 211 } 212 if (length < 0) { 213 throw new IOException("Bad record length of " + length 214 + " at byte " + toHex(currPos+5) 215 + " of file."); 216 } 217 currPos += 9 + length; 218 switch (type) { 219 case HPROF_UTF8: { 220 long id = readID(); 221 byte[] chars = new byte[(int)length - identifierSize]; 222 in.readFully(chars); 223 names.put(id, new String(chars)); 224 break; 225 } 226 case HPROF_LOAD_CLASS: { 227 int serialNo = in.readInt(); // Not used 228 long classID = readID(); 229 int stackTraceSerialNo = in.readInt(); 230 long classNameID = readID(); 231 Long classIdI = classID; 232 String nm = getNameFromID(classNameID).replace('/', '.'); 233 classNameFromObjectID.put(classIdI, nm); 234 if (classNameFromSerialNo != null) { 235 classNameFromSerialNo.put(serialNo, nm); 236 } 237 break; 238 } 239 240 case HPROF_HEAP_DUMP: { 241 if (dumpsToSkip <= 0) { 242 try { 243 readHeapDump(length, currPos); 244 } catch (EOFException exp) { 245 handleEOF(exp, snapshot); 246 } 247 if (debugLevel > 0) { 248 System.out.println(" Finished processing instances in heap dump."); 249 } 250 return snapshot; 251 } else { 252 dumpsToSkip--; 253 skipBytes(length); 254 } 255 break; 256 } 257 258 case HPROF_HEAP_DUMP_END: { 259 if (version >= VERSION_JDK6) { 260 if (dumpsToSkip <= 0) { 261 skipBytes(length); // should be no-op 262 return snapshot; 263 } else { 264 // skip this dump (of the end record for a sequence of dump segments) 265 dumpsToSkip--; 266 } 267 } else { 268 // HPROF_HEAP_DUMP_END only recognized in >= 1.0.2 269 warn("Ignoring unrecognized record type " + type); 270 } 271 skipBytes(length); // should be no-op 272 break; 273 } 274 275 case HPROF_HEAP_DUMP_SEGMENT: { 276 if (version >= VERSION_JDK6) { 277 if (dumpsToSkip <= 0) { 278 try { 279 // read the dump segment 280 readHeapDump(length, currPos); 281 } catch (EOFException exp) { 282 handleEOF(exp, snapshot); 283 } 284 } else { 285 // all segments comprising the heap dump will be skipped 286 skipBytes(length); 287 } 288 } else { 289 // HPROF_HEAP_DUMP_SEGMENT only recognized in >= 1.0.2 290 warn("Ignoring unrecognized record type " + type); 291 skipBytes(length); 292 } 293 break; 294 } 295 296 case HPROF_FRAME: { 297 if (stackFrames == null) { 298 skipBytes(length); 299 } else { 300 long id = readID(); 301 String methodName = getNameFromID(readID()); 302 String methodSig = getNameFromID(readID()); 303 String sourceFile = getNameFromID(readID()); 304 int classSer = in.readInt(); 305 String className = classNameFromSerialNo.get(classSer); 306 int lineNumber = in.readInt(); 307 if (lineNumber < StackFrame.LINE_NUMBER_NATIVE) { 308 warn("Weird stack frame line number: " + lineNumber); 309 lineNumber = StackFrame.LINE_NUMBER_UNKNOWN; 310 } 311 stackFrames.put(id, 312 new StackFrame(methodName, methodSig, 313 className, sourceFile, 314 lineNumber)); 315 } 316 break; 317 } 318 case HPROF_TRACE: { 319 if (stackTraces == null) { 320 skipBytes(length); 321 } else { 322 int serialNo = in.readInt(); 323 int threadSeq = in.readInt(); // Not used 324 StackFrame[] frames = new StackFrame[in.readInt()]; 325 for (int i = 0; i < frames.length; i++) { 326 long fid = readID(); 327 frames[i] = stackFrames.get(fid); 328 if (frames[i] == null) { 329 throw new IOException("Stack frame " + toHex(fid) + " not found"); 330 } 331 } 332 stackTraces.put(serialNo, 333 new StackTrace(frames)); 334 } 335 break; 336 } 337 case HPROF_UNLOAD_CLASS: 338 case HPROF_ALLOC_SITES: 339 case HPROF_START_THREAD: 340 case HPROF_END_THREAD: 341 case HPROF_HEAP_SUMMARY: 342 case HPROF_CPU_SAMPLES: 343 case HPROF_CONTROL_SETTINGS: 344 case HPROF_LOCKSTATS_WAIT_TIME: 345 case HPROF_LOCKSTATS_HOLD_TIME: 346 { 347 // Ignore these record types 348 skipBytes(length); 349 break; 350 } 351 default: { 352 skipBytes(length); 353 warn("Ignoring unrecognized record type " + type); 354 } 355 } 356 } 357 358 return snapshot; 359 } 360 361 public String printStackTraces() { 362 StringBuffer output = new StringBuffer(); 363 for (Map.Entry<Integer, StackTrace> entry : stackTraces.entrySet()) { 364 StackFrame[] frames = entry.getValue().getFrames(); 365 output.append("SerialNo " + entry.getKey() + "\n"); 366 for (int i = 0; i < frames.length; i++) { 367 output.append(" " + frames[i].getClassName() + "." + frames[i].getMethodName() 368 + frames[i].getMethodSignature() + " (" + frames[i].getSourceFileName() 369 + ":" + frames[i].getLineNumber() + ")" + "\n"); 370 } 371 } 372 373 System.out.println(output); 374 return output.toString(); 375 } 376 377 private void skipBytes(long length) throws IOException { 378 while (length > 0) { 379 long skipped = in.skip(length); 380 if (skipped == 0) { 381 // EOF or other problem, throw exception 382 throw new EOFException("Couldn't skip enough bytes"); 383 } 384 length -= skipped; 385 } 386 } 387 388 private int readVersionHeader() throws IOException { 389 int candidatesLeft = VERSIONS.length; 390 boolean[] matched = new boolean[VERSIONS.length]; 391 for (int i = 0; i < candidatesLeft; i++) { 392 matched[i] = true; 393 } 394 395 int pos = 0; 396 while (candidatesLeft > 0) { 397 char c = (char) in.readByte(); 398 currPos++; 399 for (int i = 0; i < VERSIONS.length; i++) { 400 if (matched[i]) { 401 if (c != VERSIONS[i].charAt(pos)) { // Not matched 402 matched[i] = false; 403 --candidatesLeft; 404 } else if (pos == VERSIONS[i].length() - 1) { // Full match 405 return i; 406 } 407 } 408 } 409 ++pos; 410 } 411 throw new IOException("Version string not recognized at byte " + (pos+3)); 412 } 413 414 private void readHeapDump(long bytesLeft, long posAtEnd) throws IOException { 415 while (bytesLeft > 0) { 416 int type = in.readUnsignedByte(); 417 if (debugLevel > 0) { 418 System.out.println(" Read heap sub-record type " + type 419 + " at position " 420 + toHex(posAtEnd - bytesLeft)); 421 } 422 bytesLeft--; 423 switch(type) { 424 case HPROF_GC_ROOT_UNKNOWN: { 425 long id = readID(); 426 bytesLeft -= identifierSize; 427 snapshot.addRoot(new Root(id, 0, Root.UNKNOWN, "")); 428 break; 429 } 430 case HPROF_GC_ROOT_THREAD_OBJ: { 431 long id = readID(); 432 int threadSeq = in.readInt(); 433 int stackSeq = in.readInt(); 434 bytesLeft -= identifierSize + 8; 435 threadObjects.put(threadSeq, 436 new ThreadObject(id, stackSeq)); 437 break; 438 } 439 case HPROF_GC_ROOT_JNI_GLOBAL: { 440 long id = readID(); 441 long globalRefId = readID(); // Ignored, for now 442 bytesLeft -= 2*identifierSize; 443 snapshot.addRoot(new Root(id, 0, Root.NATIVE_STATIC, "")); 444 break; 445 } 446 case HPROF_GC_ROOT_JNI_LOCAL: { 447 long id = readID(); 448 int threadSeq = in.readInt(); 449 int depth = in.readInt(); 450 bytesLeft -= identifierSize + 8; 451 ThreadObject to = getThreadObjectFromSequence(threadSeq); 452 StackTrace st = getStackTraceFromSerial(to.stackSeq); 453 if (st != null) { 454 st = st.traceForDepth(depth+1); 455 } 456 snapshot.addRoot(new Root(id, to.threadId, 457 Root.NATIVE_LOCAL, "", st)); 458 break; 459 } 460 case HPROF_GC_ROOT_JAVA_FRAME: { 461 long id = readID(); 462 int threadSeq = in.readInt(); 463 int depth = in.readInt(); 464 bytesLeft -= identifierSize + 8; 465 ThreadObject to = getThreadObjectFromSequence(threadSeq); 466 StackTrace st = getStackTraceFromSerial(to.stackSeq); 467 if (st != null) { 468 st = st.traceForDepth(depth+1); 469 } 470 snapshot.addRoot(new Root(id, to.threadId, 471 Root.JAVA_LOCAL, "", st)); 472 break; 473 } 474 case HPROF_GC_ROOT_NATIVE_STACK: { 475 long id = readID(); 476 int threadSeq = in.readInt(); 477 bytesLeft -= identifierSize + 4; 478 ThreadObject to = getThreadObjectFromSequence(threadSeq); 479 StackTrace st = getStackTraceFromSerial(to.stackSeq); 480 snapshot.addRoot(new Root(id, to.threadId, 481 Root.NATIVE_STACK, "", st)); 482 break; 483 } 484 case HPROF_GC_ROOT_STICKY_CLASS: { 485 long id = readID(); 486 bytesLeft -= identifierSize; 487 snapshot.addRoot(new Root(id, 0, Root.SYSTEM_CLASS, "")); 488 break; 489 } 490 case HPROF_GC_ROOT_THREAD_BLOCK: { 491 long id = readID(); 492 int threadSeq = in.readInt(); 493 bytesLeft -= identifierSize + 4; 494 ThreadObject to = getThreadObjectFromSequence(threadSeq); 495 StackTrace st = getStackTraceFromSerial(to.stackSeq); 496 snapshot.addRoot(new Root(id, to.threadId, 497 Root.THREAD_BLOCK, "", st)); 498 break; 499 } 500 case HPROF_GC_ROOT_MONITOR_USED: { 501 long id = readID(); 502 bytesLeft -= identifierSize; 503 snapshot.addRoot(new Root(id, 0, Root.BUSY_MONITOR, "")); 504 break; 505 } 506 case HPROF_GC_CLASS_DUMP: { 507 int bytesRead = readClass(); 508 bytesLeft -= bytesRead; 509 break; 510 } 511 case HPROF_GC_INSTANCE_DUMP: { 512 int bytesRead = readInstance(); 513 bytesLeft -= bytesRead; 514 break; 515 } 516 case HPROF_GC_OBJ_ARRAY_DUMP: { 517 long bytesRead = readArray(false); 518 bytesLeft -= bytesRead; 519 break; 520 } 521 case HPROF_GC_PRIM_ARRAY_DUMP: { 522 long bytesRead = readArray(true); 523 bytesLeft -= bytesRead; 524 break; 525 } 526 default: { 527 throw new IOException("Unrecognized heap dump sub-record type: " + type); 528 } 529 } 530 } 531 if (bytesLeft != 0) { 532 warn("Error reading heap dump or heap dump segment: Byte count is " + bytesLeft + " instead of 0"); 533 skipBytes(bytesLeft); 534 } 535 if (debugLevel > 0) { 536 System.out.println(" Finished heap sub-records."); 537 } 538 } 539 540 private long readID() throws IOException { 541 return (identifierSize == 4)? 542 (Snapshot.SMALL_ID_MASK & (long)in.readInt()) : in.readLong(); 543 } 544 545 // 546 // Read a java value. If result is non-null, it's expected to be an 547 // array of one element. We use it to fake multiple return values. 548 // @returns the number of bytes read 549 // 550 private int readValue(JavaThing[] resultArr) throws IOException { 551 byte type = in.readByte(); 552 return 1 + readValueForType(type, resultArr); 553 } 554 555 private int readValueForType(byte type, JavaThing[] resultArr) 556 throws IOException { 557 if (version >= VERSION_JDK12BETA4) { 558 type = signatureFromTypeId(type); 559 } 560 return readValueForTypeSignature(type, resultArr); 561 } 562 563 private int readValueForTypeSignature(byte type, JavaThing[] resultArr) 564 throws IOException { 565 switch (type) { 566 case '[': 567 case 'L': { 568 long id = readID(); 569 if (resultArr != null) { 570 resultArr[0] = new JavaObjectRef(id); 571 } 572 return identifierSize; 573 } 574 case 'Z': { 575 int b = in.readByte(); 576 if (b != 0 && b != 1) { 577 warn("Illegal boolean value read"); 578 } 579 if (resultArr != null) { 580 resultArr[0] = new JavaBoolean(b != 0); 581 } 582 return 1; 583 } 584 case 'B': { 585 byte b = in.readByte(); 586 if (resultArr != null) { 587 resultArr[0] = new JavaByte(b); 588 } 589 return 1; 590 } 591 case 'S': { 592 short s = in.readShort(); 593 if (resultArr != null) { 594 resultArr[0] = new JavaShort(s); 595 } 596 return 2; 597 } 598 case 'C': { 599 char ch = in.readChar(); 600 if (resultArr != null) { 601 resultArr[0] = new JavaChar(ch); 602 } 603 return 2; 604 } 605 case 'I': { 606 int val = in.readInt(); 607 if (resultArr != null) { 608 resultArr[0] = new JavaInt(val); 609 } 610 return 4; 611 } 612 case 'J': { 613 long val = in.readLong(); 614 if (resultArr != null) { 615 resultArr[0] = new JavaLong(val); 616 } 617 return 8; 618 } 619 case 'F': { 620 float val = in.readFloat(); 621 if (resultArr != null) { 622 resultArr[0] = new JavaFloat(val); 623 } 624 return 4; 625 } 626 case 'D': { 627 double val = in.readDouble(); 628 if (resultArr != null) { 629 resultArr[0] = new JavaDouble(val); 630 } 631 return 8; 632 } 633 default: { 634 throw new IOException("Bad value signature: " + type); 635 } 636 } 637 } 638 639 private ThreadObject getThreadObjectFromSequence(int threadSeq) 640 throws IOException { 641 ThreadObject to = threadObjects.get(threadSeq); 642 if (to == null) { 643 throw new IOException("Thread " + threadSeq + 644 " not found for JNI local ref"); 645 } 646 return to; 647 } 648 649 private String getNameFromID(long id) throws IOException { 650 return getNameFromID(Long.valueOf(id)); 651 } 652 653 private String getNameFromID(Long id) throws IOException { 654 if (id.longValue() == 0L) { 655 return ""; 656 } 657 String result = names.get(id); 658 if (result == null) { 659 warn("Name not found at " + toHex(id.longValue())); 660 return "unresolved name " + toHex(id.longValue()); 661 } 662 return result; 663 } 664 665 private StackTrace getStackTraceFromSerial(int ser) throws IOException { 666 if (stackTraces == null) { 667 return null; 668 } 669 StackTrace result = stackTraces.get(ser); 670 if (result == null) { 671 warn("Stack trace not found for serial # " + ser); 672 } 673 return result; 674 } 675 676 // 677 // Handle a HPROF_GC_CLASS_DUMP 678 // Return number of bytes read 679 // 680 private int readClass() throws IOException { 681 long id = readID(); 682 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 683 long superId = readID(); 684 long classLoaderId = readID(); 685 long signersId = readID(); 686 long protDomainId = readID(); 687 long reserved1 = readID(); 688 long reserved2 = readID(); 689 int instanceSize = in.readInt(); 690 int bytesRead = 7 * identifierSize + 8; 691 692 int numConstPoolEntries = in.readUnsignedShort(); 693 bytesRead += 2; 694 for (int i = 0; i < numConstPoolEntries; i++) { 695 int index = in.readUnsignedShort(); // unused 696 bytesRead += 2; 697 bytesRead += readValue(null); // We ignore the values 698 } 699 700 int numStatics = in.readUnsignedShort(); 701 bytesRead += 2; 702 JavaThing[] valueBin = new JavaThing[1]; 703 JavaStatic[] statics = new JavaStatic[numStatics]; 704 for (int i = 0; i < numStatics; i++) { 705 long nameId = readID(); 706 bytesRead += identifierSize; 707 byte type = in.readByte(); 708 bytesRead++; 709 bytesRead += readValueForType(type, valueBin); 710 String fieldName = getNameFromID(nameId); 711 if (version >= VERSION_JDK12BETA4) { 712 type = signatureFromTypeId(type); 713 } 714 String signature = "" + ((char) type); 715 JavaField f = new JavaField(fieldName, signature); 716 statics[i] = new JavaStatic(f, valueBin[0]); 717 } 718 719 int numFields = in.readUnsignedShort(); 720 bytesRead += 2; 721 JavaField[] fields = new JavaField[numFields]; 722 for (int i = 0; i < numFields; i++) { 723 long nameId = readID(); 724 bytesRead += identifierSize; 725 byte type = in.readByte(); 726 bytesRead++; 727 String fieldName = getNameFromID(nameId); 728 if (version >= VERSION_JDK12BETA4) { 729 type = signatureFromTypeId(type); 730 } 731 String signature = "" + ((char) type); 732 fields[i] = new JavaField(fieldName, signature); 733 } 734 String name = classNameFromObjectID.get(id); 735 if (name == null) { 736 warn("Class name not found for " + toHex(id)); 737 name = "unknown-name@" + toHex(id); 738 } 739 JavaClass c = new JavaClass(id, name, superId, classLoaderId, signersId, 740 protDomainId, fields, statics, 741 instanceSize); 742 snapshot.addClass(id, c); 743 snapshot.setSiteTrace(c, stackTrace); 744 745 return bytesRead; 746 } 747 748 private String toHex(long addr) { 749 return jdk.test.lib.hprof.util.Misc.toHex(addr); 750 } 751 752 // 753 // Handle a HPROF_GC_INSTANCE_DUMP 754 // Return number of bytes read 755 // 756 private int readInstance() throws IOException { 757 long start = in.position(); 758 long id = readID(); 759 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 760 long classID = readID(); 761 JavaClass searchedClass = snapshot.findClass( 762 "0x" + Long.toHexString(classID)); 763 if (searchedClass == null) { 764 throw new IOException( 765 "Class Record for 0x" + Long.toHexString(classID) + " not found"); 766 } 767 int bytesFollowing = in.readInt(); 768 int bytesRead = (2 * identifierSize) + 8 + bytesFollowing; 769 JavaObject jobj = new JavaObject(classID, start); 770 skipBytes(bytesFollowing); 771 snapshot.addHeapObject(id, jobj); 772 snapshot.setSiteTrace(jobj, stackTrace); 773 return bytesRead; 774 } 775 776 // 777 // Handle a HPROF_GC_OBJ_ARRAY_DUMP or HPROF_GC_PRIM_ARRAY_DUMP 778 // Return number of bytes read 779 // 780 private long readArray(boolean isPrimitive) throws IOException { 781 long start = in.position(); 782 long id = readID(); 783 StackTrace stackTrace = getStackTraceFromSerial(in.readInt()); 784 int num = in.readInt(); 785 long bytesRead = identifierSize + 8; 786 long elementClassID; 787 if (isPrimitive) { 788 elementClassID = in.readByte(); 789 bytesRead++; 790 } else { 791 elementClassID = readID(); 792 bytesRead += identifierSize; 793 } 794 795 // Check for primitive arrays: 796 byte primitiveSignature = 0x00; 797 int elSize = 0; 798 if (isPrimitive || version < VERSION_JDK12BETA4) { 799 switch ((int)elementClassID) { 800 case T_BOOLEAN: { 801 primitiveSignature = (byte) 'Z'; 802 elSize = 1; 803 break; 804 } 805 case T_CHAR: { 806 primitiveSignature = (byte) 'C'; 807 elSize = 2; 808 break; 809 } 810 case T_FLOAT: { 811 primitiveSignature = (byte) 'F'; 812 elSize = 4; 813 break; 814 } 815 case T_DOUBLE: { 816 primitiveSignature = (byte) 'D'; 817 elSize = 8; 818 break; 819 } 820 case T_BYTE: { 821 primitiveSignature = (byte) 'B'; 822 elSize = 1; 823 break; 824 } 825 case T_SHORT: { 826 primitiveSignature = (byte) 'S'; 827 elSize = 2; 828 break; 829 } 830 case T_INT: { 831 primitiveSignature = (byte) 'I'; 832 elSize = 4; 833 break; 834 } 835 case T_LONG: { 836 primitiveSignature = (byte) 'J'; 837 elSize = 8; 838 break; 839 } 840 } 841 if (version >= VERSION_JDK12BETA4 && primitiveSignature == 0x00) { 842 throw new IOException("Unrecognized typecode: " 843 + elementClassID); 844 } 845 } 846 if (primitiveSignature != 0x00) { 847 long size = elSize * (long)num; 848 bytesRead += size; 849 JavaValueArray va = new JavaValueArray(primitiveSignature, start); 850 skipBytes(size); 851 snapshot.addHeapObject(id, va); 852 snapshot.setSiteTrace(va, stackTrace); 853 } else { 854 long sz = (long)num * identifierSize; 855 bytesRead += sz; 856 JavaObjectArray arr = new JavaObjectArray(elementClassID, start); 857 skipBytes(sz); 858 snapshot.addHeapObject(id, arr); 859 snapshot.setSiteTrace(arr, stackTrace); 860 } 861 return bytesRead; 862 } 863 864 private byte signatureFromTypeId(byte typeId) throws IOException { 865 switch (typeId) { 866 case T_CLASS: { 867 return (byte) 'L'; 868 } 869 case T_BOOLEAN: { 870 return (byte) 'Z'; 871 } 872 case T_CHAR: { 873 return (byte) 'C'; 874 } 875 case T_FLOAT: { 876 return (byte) 'F'; 877 } 878 case T_DOUBLE: { 879 return (byte) 'D'; 880 } 881 case T_BYTE: { 882 return (byte) 'B'; 883 } 884 case T_SHORT: { 885 return (byte) 'S'; 886 } 887 case T_INT: { 888 return (byte) 'I'; 889 } 890 case T_LONG: { 891 return (byte) 'J'; 892 } 893 default: { 894 throw new IOException("Invalid type id of " + typeId); 895 } 896 } 897 } 898 899 private void handleEOF(EOFException exp, Snapshot snapshot) { 900 if (debugLevel > 0) { 901 exp.printStackTrace(); 902 } 903 warn("Unexpected EOF. Will miss information..."); 904 // we have EOF, we have to tolerate missing references 905 snapshot.setUnresolvedObjectsOK(true); 906 } 907 908 private void warn(String msg) { 909 System.out.println("WARNING: " + msg); 910 } 911 912 // 913 // A trivial data-holder class for HPROF_GC_ROOT_THREAD_OBJ. 914 // 915 private class ThreadObject { 916 917 long threadId; 918 int stackSeq; 919 920 ThreadObject(long threadId, int stackSeq) { 921 this.threadId = threadId; 922 this.stackSeq = stackSeq; 923 } 924 } 925 926 }