1 /* 2 * Copyright (c) 2000, 2018, 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; 26 27 import java.io.*; 28 import java.util.*; 29 import sun.jvm.hotspot.debugger.*; 30 import sun.jvm.hotspot.types.*; 31 import sun.jvm.hotspot.types.basic.*; 32 import sun.jvm.hotspot.utilities.*; 33 34 /** <P> This is the cross-platform TypeDataBase used by the Oop 35 hierarchy. The decision was made to make this cross-platform by 36 having the VM export the necessary symbols via a built-in table; 37 see src/share/vm/runtime/vmStructs.[ch]pp for more details. </P> 38 39 <P> <B>WARNING</B>: clients should refer to this class through the 40 TypeDataBase interface and not directly to the HotSpotTypeDataBase 41 type. </P> 42 43 <P> NOTE: since we are fetching the sizes of the Java primitive types 44 */ 45 46 public class HotSpotTypeDataBase extends BasicTypeDataBase { 47 private Debugger symbolLookup; 48 private String[] jvmLibNames; 49 private static final int UNINITIALIZED_SIZE = -1; 50 private static final int C_INT8_SIZE = 1; 51 private static final int C_INT32_SIZE = 4; 52 private static final int C_INT64_SIZE = 8; 53 private static int pointerSize = UNINITIALIZED_SIZE; 54 // Counter to ensure read loops terminate: 55 private static final int MAX_DUPLICATE_DEFINITIONS = 100; 56 private int duplicateDefCount = 0; 57 58 private static final boolean DEBUG; 59 static { 60 DEBUG = System.getProperty("sun.jvm.hotspot.HotSpotTypeDataBase.DEBUG") 61 != null; 62 } 63 64 /** <P> This requires a SymbolLookup mechanism as well as the 65 MachineDescription. Note that we do not need a NameMangler since 66 we use the vmStructs mechanism to avoid looking up C++ 67 symbols. </P> 68 69 <P> NOTE that it is guaranteed that this constructor will not 70 attempt to fetch any Java values from the remote process, only C 71 integers and addresses. This is required because we are fetching 72 the sizes of the Java primitive types from the remote process, 73 implying that attempting to fetch them before their sizes are 74 known is illegal. </P> 75 76 <P> Throws NoSuchSymbolException if a problem occurred while 77 looking up one of the bootstrapping symbols related to the 78 VMStructs table in the remote VM; this may indicate that the 79 remote process is not actually a HotSpot VM. </P> 80 */ HotSpotTypeDataBase(MachineDescription machDesc, VtblAccess vtblAccess, Debugger symbolLookup, String[] jvmLibNames)81 public HotSpotTypeDataBase(MachineDescription machDesc, 82 VtblAccess vtblAccess, 83 Debugger symbolLookup, 84 String[] jvmLibNames) throws NoSuchSymbolException { 85 super(machDesc, vtblAccess); 86 this.symbolLookup = symbolLookup; 87 this.jvmLibNames = jvmLibNames; 88 89 readVMTypes(); 90 initializePrimitiveTypes(); 91 readVMStructs(); 92 readVMIntConstants(); 93 readVMLongConstants(); 94 readExternalDefinitions(); 95 } 96 lookupType(String cTypeName, boolean throwException)97 public Type lookupType(String cTypeName, boolean throwException) { 98 Type fieldType = super.lookupType(cTypeName, false); 99 if (fieldType == null && cTypeName.startsWith("const ")) { 100 fieldType = (BasicType)lookupType(cTypeName.substring(6), false); 101 } 102 if (fieldType == null && cTypeName.endsWith(" const")) { 103 fieldType = (BasicType)lookupType(cTypeName.substring(0, cTypeName.length() - 6), false); 104 } 105 if (fieldType == null) { 106 if (cTypeName.startsWith("GrowableArray<") && cTypeName.endsWith(">")) { 107 String ttype = cTypeName.substring("GrowableArray<".length(), 108 cTypeName.length() - 1); 109 Type templateType = lookupType(ttype, false); 110 if (templateType == null && typeNameIsPointerType(ttype)) { 111 templateType = recursiveCreateBasicPointerType(ttype); 112 } 113 if (templateType == null) { 114 lookupOrFail(ttype); 115 } 116 117 BasicType basicTargetType = createBasicType(cTypeName, false, false, false); 118 119 // transfer fields from GrowableArrayBase to template instance 120 BasicType generic = lookupOrFail("GrowableArrayBase"); 121 BasicType specific = lookupOrFail("GrowableArray<int>"); 122 basicTargetType.setSize(specific.getSize()); 123 Iterator fields = generic.getFields(); 124 while (fields.hasNext()) { 125 Field f = (Field)fields.next(); 126 basicTargetType.addField(internalCreateField(basicTargetType, f.getName(), 127 f.getType(), f.isStatic(), 128 f.getOffset(), null)); 129 } 130 fieldType = basicTargetType; 131 } 132 } 133 if (fieldType == null && typeNameIsPointerType(cTypeName)) { 134 fieldType = recursiveCreateBasicPointerType(cTypeName); 135 } 136 if (fieldType == null && throwException) { 137 super.lookupType(cTypeName, true); 138 } 139 return fieldType; 140 } 141 readVMTypes()142 private void readVMTypes() { 143 // Get the variables we need in order to traverse the VMTypeEntry[] 144 long typeEntryTypeNameOffset; 145 long typeEntrySuperclassNameOffset; 146 long typeEntryIsOopTypeOffset; 147 long typeEntryIsIntegerTypeOffset; 148 long typeEntryIsUnsignedOffset; 149 long typeEntrySizeOffset; 150 long typeEntryArrayStride; 151 152 // Fetch the address of the VMTypeEntry*. We get this symbol first 153 // and try to use it to make sure that symbol lookup is working. 154 Address entryAddr = lookupInProcess("gHotSpotVMTypes"); 155 // System.err.println("gHotSpotVMTypes address = " + entryAddr); 156 // Dereference this once to get the pointer to the first VMTypeEntry 157 // dumpMemory(entryAddr, 80); 158 entryAddr = entryAddr.getAddressAt(0); 159 160 if (entryAddr == null) { 161 throw new RuntimeException("gHotSpotVMTypes was not initialized properly in the remote process; can not continue"); 162 } 163 164 typeEntryTypeNameOffset = getLongValueFromProcess("gHotSpotVMTypeEntryTypeNameOffset"); 165 typeEntrySuperclassNameOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySuperclassNameOffset"); 166 typeEntryIsOopTypeOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsOopTypeOffset"); 167 typeEntryIsIntegerTypeOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsIntegerTypeOffset"); 168 typeEntryIsUnsignedOffset = getLongValueFromProcess("gHotSpotVMTypeEntryIsUnsignedOffset"); 169 typeEntrySizeOffset = getLongValueFromProcess("gHotSpotVMTypeEntrySizeOffset"); 170 typeEntryArrayStride = getLongValueFromProcess("gHotSpotVMTypeEntryArrayStride"); 171 172 if (typeEntryArrayStride == 0L) { 173 throw new RuntimeException("zero stride: cannot read types."); 174 } 175 176 // Start iterating down it until we find an entry with no name 177 Address typeNameAddr = null; 178 do { 179 // Fetch the type name first 180 typeNameAddr = entryAddr.getAddressAt(typeEntryTypeNameOffset); 181 if (typeNameAddr != null) { 182 String typeName = CStringUtilities.getString(typeNameAddr); 183 184 String superclassName = null; 185 Address superclassNameAddr = entryAddr.getAddressAt(typeEntrySuperclassNameOffset); 186 if (superclassNameAddr != null) { 187 superclassName = CStringUtilities.getString(superclassNameAddr); 188 } 189 190 boolean isOopType = (entryAddr.getCIntegerAt(typeEntryIsOopTypeOffset, C_INT32_SIZE, false) != 0); 191 boolean isIntegerType = (entryAddr.getCIntegerAt(typeEntryIsIntegerTypeOffset, C_INT32_SIZE, false) != 0); 192 boolean isUnsigned = (entryAddr.getCIntegerAt(typeEntryIsUnsignedOffset, C_INT32_SIZE, false) != 0); 193 long size = entryAddr.getCIntegerAt(typeEntrySizeOffset, C_INT64_SIZE, true); 194 195 createType(typeName, superclassName, isOopType, isIntegerType, isUnsigned, size); 196 if (pointerSize == UNINITIALIZED_SIZE && typeName.equals("void*")) { 197 pointerSize = (int)size; 198 } 199 } 200 201 entryAddr = entryAddr.addOffsetTo(typeEntryArrayStride); 202 } while (typeNameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS); 203 204 if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) { 205 throw new RuntimeException("too many duplicate definitions"); 206 } 207 } 208 initializePrimitiveTypes()209 private void initializePrimitiveTypes() { 210 // Look up the needed primitive types by name...they had better be present 211 setJBooleanType(lookupPrimitiveType("jboolean")); 212 setJByteType (lookupPrimitiveType("jbyte")); 213 setJCharType (lookupPrimitiveType("jchar")); 214 setJDoubleType (lookupPrimitiveType("jdouble")); 215 setJFloatType (lookupPrimitiveType("jfloat")); 216 setJIntType (lookupPrimitiveType("jint")); 217 setJLongType (lookupPrimitiveType("jlong")); 218 setJShortType (lookupPrimitiveType("jshort")); 219 220 // Indicate that these are the Java primitive types 221 ((BasicType) getJBooleanType()).setIsJavaPrimitiveType(true); 222 ((BasicType) getJByteType()).setIsJavaPrimitiveType(true); 223 ((BasicType) getJCharType()).setIsJavaPrimitiveType(true); 224 ((BasicType) getJDoubleType()).setIsJavaPrimitiveType(true); 225 ((BasicType) getJFloatType()).setIsJavaPrimitiveType(true); 226 ((BasicType) getJIntType()).setIsJavaPrimitiveType(true); 227 ((BasicType) getJLongType()).setIsJavaPrimitiveType(true); 228 ((BasicType) getJShortType()).setIsJavaPrimitiveType(true); 229 } 230 lookupPrimitiveType(String typeName)231 private Type lookupPrimitiveType(String typeName) { 232 Type type = lookupType(typeName, false); 233 if (type == null) { 234 throw new RuntimeException("Error initializing the HotSpotDataBase: could not find the primitive type \"" + 235 typeName + "\" in the remote VM's VMStructs table. This type is required in " + 236 "order to determine the size of Java primitive types. Can not continue."); 237 } 238 return type; 239 } 240 readExternalDefinitions()241 private void readExternalDefinitions() { 242 String file = System.getProperty("sun.jvm.hotspot.typedb"); 243 if (file != null) { 244 System.out.println("Reading " + file); 245 BufferedReader in = null; 246 try { 247 StreamTokenizer t = new StreamTokenizer(in = new BufferedReader(new InputStreamReader(new FileInputStream(file)))); 248 t.resetSyntax(); 249 t.wordChars('\u0000','\uFFFF'); 250 t.whitespaceChars(' ', ' '); 251 t.whitespaceChars('\n', '\n'); 252 t.whitespaceChars('\r', '\r'); 253 t.quoteChar('\"'); 254 t.eolIsSignificant(true); 255 while (t.nextToken() != StreamTokenizer.TT_EOF) { 256 if (t.ttype == StreamTokenizer.TT_EOL) { 257 continue; 258 } 259 260 if (t.sval.equals("field")) { 261 t.nextToken(); 262 BasicType containingType = (BasicType)lookupType(t.sval); 263 t.nextToken(); 264 String fieldName = t.sval; 265 266 // The field's Type must already be in the database -- no exceptions 267 t.nextToken(); 268 Type fieldType = lookupType(t.sval); 269 t.nextToken(); 270 boolean isStatic = Boolean.valueOf(t.sval).booleanValue(); 271 t.nextToken(); 272 long offset = Long.parseLong(t.sval); 273 t.nextToken(); 274 Address staticAddress = null; 275 if (isStatic) { 276 throw new InternalError("static fields not supported"); 277 } 278 279 // check to see if the field already exists 280 Iterator i = containingType.getFields(); 281 boolean defined = false; 282 while (i.hasNext()) { 283 Field f = (Field) i.next(); 284 if (f.getName().equals(fieldName)) { 285 if (f.isStatic() != isStatic) { 286 throw new RuntimeException("static/nonstatic mismatch: " + fieldName); 287 } 288 if (!isStatic) { 289 if (f.getOffset() != offset) { 290 throw new RuntimeException("bad redefinition of field offset: " + fieldName); 291 } 292 } else { 293 if (!f.getStaticFieldAddress().equals(staticAddress)) { 294 throw new RuntimeException("bad redefinition of field location: " + fieldName); 295 } 296 } 297 if (f.getType() != fieldType) { 298 System.out.println(fieldType); 299 System.out.println(f.getType()); 300 throw new RuntimeException("bad redefinition of field type: " + fieldName); 301 } 302 defined = true; 303 break; 304 } 305 } 306 307 if (!defined) { 308 // Create field by type 309 createField(containingType, 310 fieldName, fieldType, 311 isStatic, 312 offset, 313 staticAddress); 314 } 315 } else if (t.sval.equals("type")) { 316 t.nextToken(); 317 String typeName = t.sval; 318 t.nextToken(); 319 String superclassName = t.sval; 320 if (superclassName.equals("null")) { 321 superclassName = null; 322 } 323 t.nextToken(); 324 boolean isOop = Boolean.valueOf(t.sval).booleanValue(); 325 t.nextToken(); 326 boolean isInteger = Boolean.valueOf(t.sval).booleanValue(); 327 t.nextToken(); 328 boolean isUnsigned = Boolean.valueOf(t.sval).booleanValue(); 329 t.nextToken(); 330 long size = Long.parseLong(t.sval); 331 332 BasicType type = null; 333 try { 334 type = (BasicType)lookupType(typeName); 335 } catch (RuntimeException e) { 336 } 337 if (type != null) { 338 if (type.isOopType() != isOop) { 339 throw new RuntimeException("oop mismatch in type definition: " + typeName); 340 } 341 if (type.isCIntegerType() != isInteger) { 342 throw new RuntimeException("integer type mismatch in type definition: " + typeName); 343 } 344 if (type.isCIntegerType() && (((CIntegerType)type).isUnsigned()) != isUnsigned) { 345 throw new RuntimeException("unsigned mismatch in type definition: " + typeName); 346 } 347 if (type.getSuperclass() == null) { 348 if (superclassName != null) { 349 if (type.getSize() == -1) { 350 type.setSuperclass(lookupType(superclassName)); 351 } else { 352 throw new RuntimeException("unexpected superclass in type definition: " + typeName); 353 } 354 } 355 } else { 356 if (superclassName == null) { 357 throw new RuntimeException("missing superclass in type definition: " + typeName); 358 } 359 if (!type.getSuperclass().getName().equals(superclassName)) { 360 throw new RuntimeException("incorrect superclass in type definition: " + typeName); 361 } 362 } 363 if (type.getSize() != size) { 364 if (type.getSize() == -1 || type.getSize() == 0) { 365 type.setSize(size); 366 } else { 367 throw new RuntimeException("size mismatch in type definition: " + typeName + ": " + type.getSize() + " != " + size); 368 } 369 } 370 } 371 372 if (lookupType(typeName, false) == null) { 373 // Create type 374 createType(typeName, superclassName, isOop, isInteger, isUnsigned, size); 375 } 376 } else { 377 throw new InternalError("\"" + t.sval + "\""); 378 } 379 } 380 } catch (IOException ioe) { 381 ioe.printStackTrace(); 382 } finally { 383 try { 384 in.close(); 385 } catch (Exception e) { 386 } 387 } 388 } 389 } 390 readVMStructs()391 private void readVMStructs() { 392 // Get the variables we need in order to traverse the VMStructEntry[] 393 long structEntryTypeNameOffset; 394 long structEntryFieldNameOffset; 395 long structEntryTypeStringOffset; 396 long structEntryIsStaticOffset; 397 long structEntryOffsetOffset; 398 long structEntryAddressOffset; 399 long structEntryArrayStride; 400 401 structEntryTypeNameOffset = getLongValueFromProcess("gHotSpotVMStructEntryTypeNameOffset"); 402 structEntryFieldNameOffset = getLongValueFromProcess("gHotSpotVMStructEntryFieldNameOffset"); 403 structEntryTypeStringOffset = getLongValueFromProcess("gHotSpotVMStructEntryTypeStringOffset"); 404 structEntryIsStaticOffset = getLongValueFromProcess("gHotSpotVMStructEntryIsStaticOffset"); 405 structEntryOffsetOffset = getLongValueFromProcess("gHotSpotVMStructEntryOffsetOffset"); 406 structEntryAddressOffset = getLongValueFromProcess("gHotSpotVMStructEntryAddressOffset"); 407 structEntryArrayStride = getLongValueFromProcess("gHotSpotVMStructEntryArrayStride"); 408 409 if (structEntryArrayStride == 0L) { 410 throw new RuntimeException("zero stride: cannot read types."); 411 } 412 413 // Fetch the address of the VMStructEntry* 414 Address entryAddr = lookupInProcess("gHotSpotVMStructs"); 415 // Dereference this once to get the pointer to the first VMStructEntry 416 entryAddr = entryAddr.getAddressAt(0); 417 if (entryAddr == null) { 418 throw new RuntimeException("gHotSpotVMStructs was not initialized properly in the remote process; can not continue"); 419 } 420 421 // Start iterating down it until we find an entry with no name 422 Address fieldNameAddr = null; 423 String typeName = null; 424 String fieldName = null; 425 String typeString = null; 426 boolean isStatic = false; 427 long offset = 0; 428 Address staticFieldAddr = null; 429 long size = 0; 430 long index = 0; 431 String opaqueName = "<opaque>"; 432 lookupOrCreateClass(opaqueName, false, false, false); 433 434 do { 435 // Fetch the field name first 436 fieldNameAddr = entryAddr.getAddressAt(structEntryFieldNameOffset); 437 if (fieldNameAddr != null) { 438 fieldName = CStringUtilities.getString(fieldNameAddr); 439 440 // Now the rest of the names. Keep in mind that the type name 441 // may be NULL, indicating that the type is opaque. 442 Address addr = entryAddr.getAddressAt(structEntryTypeNameOffset); 443 if (addr == null) { 444 throw new RuntimeException("gHotSpotVMStructs unexpectedly had a NULL type name at index " + index); 445 } 446 typeName = CStringUtilities.getString(addr); 447 448 addr = entryAddr.getAddressAt(structEntryTypeStringOffset); 449 if (addr == null) { 450 typeString = opaqueName; 451 } else { 452 typeString = CStringUtilities.getString(addr); 453 } 454 455 isStatic = !(entryAddr.getCIntegerAt(structEntryIsStaticOffset, C_INT32_SIZE, false) == 0); 456 if (isStatic) { 457 staticFieldAddr = entryAddr.getAddressAt(structEntryAddressOffset); 458 offset = 0; 459 } else { 460 offset = entryAddr.getCIntegerAt(structEntryOffsetOffset, C_INT64_SIZE, true); 461 staticFieldAddr = null; 462 } 463 464 // The containing Type must already be in the database -- no exceptions 465 BasicType containingType = lookupOrFail(typeName); 466 467 // The field's Type must already be in the database -- no exceptions 468 BasicType fieldType = (BasicType)lookupType(typeString); 469 470 // Create field by type 471 createField(containingType, fieldName, fieldType, 472 isStatic, offset, staticFieldAddr); 473 } 474 475 ++index; 476 entryAddr = entryAddr.addOffsetTo(structEntryArrayStride); 477 } while (fieldNameAddr != null); 478 } 479 readVMIntConstants()480 private void readVMIntConstants() { 481 // Get the variables we need in order to traverse the VMIntConstantEntry[] 482 long intConstantEntryNameOffset; 483 long intConstantEntryValueOffset; 484 long intConstantEntryArrayStride; 485 486 intConstantEntryNameOffset = getLongValueFromProcess("gHotSpotVMIntConstantEntryNameOffset"); 487 intConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMIntConstantEntryValueOffset"); 488 intConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMIntConstantEntryArrayStride"); 489 490 if (intConstantEntryArrayStride == 0L) { 491 throw new RuntimeException("zero stride: cannot read types."); 492 } 493 494 495 // Fetch the address of the VMIntConstantEntry* 496 Address entryAddr = lookupInProcess("gHotSpotVMIntConstants"); 497 // Dereference this once to get the pointer to the first VMIntConstantEntry 498 entryAddr = entryAddr.getAddressAt(0); 499 if (entryAddr == null) { 500 throw new RuntimeException("gHotSpotVMIntConstants was not initialized properly in the remote process; can not continue"); 501 } 502 503 // Start iterating down it until we find an entry with no name 504 Address nameAddr = null; 505 do { 506 // Fetch the type name first 507 nameAddr = entryAddr.getAddressAt(intConstantEntryNameOffset); 508 if (nameAddr != null) { 509 String name = CStringUtilities.getString(nameAddr); 510 int value = (int) entryAddr.getCIntegerAt(intConstantEntryValueOffset, C_INT32_SIZE, false); 511 512 // Be a little resilient 513 Integer oldValue = lookupIntConstant(name, false); 514 if (oldValue == null) { 515 addIntConstant(name, value); 516 } else { 517 if (oldValue.intValue() != value) { 518 throw new RuntimeException("Error: the integer constant \"" + name + 519 "\" had its value redefined (old was " + oldValue + 520 ", new is " + value + ". Aborting."); 521 } else { 522 System.err.println("Warning: the int constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMIntConstants) " + 523 "had its value declared as " + value + " twice. Continuing."); 524 duplicateDefCount++; 525 } 526 } 527 } 528 529 entryAddr = entryAddr.addOffsetTo(intConstantEntryArrayStride); 530 } while (nameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS); 531 532 if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) { 533 throw new RuntimeException("too many duplicate definitions"); 534 } 535 } 536 readVMLongConstants()537 private void readVMLongConstants() { 538 // Get the variables we need in order to traverse the VMLongConstantEntry[] 539 long longConstantEntryNameOffset; 540 long longConstantEntryValueOffset; 541 long longConstantEntryArrayStride; 542 543 longConstantEntryNameOffset = getLongValueFromProcess("gHotSpotVMLongConstantEntryNameOffset"); 544 longConstantEntryValueOffset = getLongValueFromProcess("gHotSpotVMLongConstantEntryValueOffset"); 545 longConstantEntryArrayStride = getLongValueFromProcess("gHotSpotVMLongConstantEntryArrayStride"); 546 547 if (longConstantEntryArrayStride == 0L) { 548 throw new RuntimeException("zero stride: cannot read types."); 549 } 550 551 // Fetch the address of the VMLongConstantEntry* 552 Address entryAddr = lookupInProcess("gHotSpotVMLongConstants"); 553 // Dereference this once to get the pointer to the first VMLongConstantEntry 554 entryAddr = entryAddr.getAddressAt(0); 555 if (entryAddr == null) { 556 throw new RuntimeException("gHotSpotVMLongConstants was not initialized properly in the remote process; can not continue"); 557 } 558 559 // Start iterating down it until we find an entry with no name 560 Address nameAddr = null; 561 do { 562 // Fetch the type name first 563 nameAddr = entryAddr.getAddressAt(longConstantEntryNameOffset); 564 if (nameAddr != null) { 565 String name = CStringUtilities.getString(nameAddr); 566 long value = entryAddr.getCIntegerAt(longConstantEntryValueOffset, C_INT64_SIZE, true); 567 568 // Be a little resilient 569 Long oldValue = lookupLongConstant(name, false); 570 if (oldValue == null) { 571 addLongConstant(name, value); 572 } else { 573 if (oldValue.longValue() != value) { 574 throw new RuntimeException("Error: the long constant \"" + name + 575 "\" had its value redefined (old was " + oldValue + 576 ", new is " + value + ". Aborting."); 577 } else { 578 System.err.println("Warning: the long constant \"" + name + "\" (declared in the remote VM in VMStructs::localHotSpotVMLongConstants) " + 579 "had its value declared as " + value + " twice. Continuing."); 580 duplicateDefCount++; 581 } 582 } 583 } 584 585 entryAddr = entryAddr.addOffsetTo(longConstantEntryArrayStride); 586 } while (nameAddr != null && duplicateDefCount < MAX_DUPLICATE_DEFINITIONS); 587 588 if (duplicateDefCount >= MAX_DUPLICATE_DEFINITIONS) { 589 throw new RuntimeException("too many duplicate definitions."); 590 } 591 } 592 lookupOrFail(String typeName)593 private BasicType lookupOrFail(String typeName) { 594 BasicType type = (BasicType) lookupType(typeName, false); 595 if (type == null) { 596 throw new RuntimeException("Type \"" + typeName + "\", referenced in VMStructs::localHotSpotVMStructs in the remote VM, " + 597 "was not present in the remote VMStructs::localHotSpotVMTypes table (should have been caught " + 598 "in the debug build of that VM). Can not continue."); 599 } 600 return type; 601 } 602 getLongValueFromProcess(String symbol)603 private long getLongValueFromProcess(String symbol) { 604 return lookupInProcess(symbol).getCIntegerAt(0, C_INT64_SIZE, true); 605 } 606 lookupInProcess(String symbol)607 private Address lookupInProcess(String symbol) throws NoSuchSymbolException { 608 // FIXME: abstract away the loadobject name 609 for (int i = 0; i < jvmLibNames.length; i++) { 610 Address addr = symbolLookup.lookup(jvmLibNames[i], symbol); 611 if (addr != null) { 612 return addr; 613 } 614 } 615 String errStr = "("; 616 for (int i = 0; i < jvmLibNames.length; i++) { 617 errStr += jvmLibNames[i]; 618 if (i < jvmLibNames.length - 1) { 619 errStr += ", "; 620 } 621 } 622 errStr += ")"; 623 throw new NoSuchSymbolException(symbol, 624 "Could not find symbol \"" + symbol + 625 "\" in any of the known library names " + 626 errStr); 627 } 628 lookupOrCreateClass(String typeName, boolean isOopType, boolean isIntegerType, boolean isUnsigned)629 private BasicType lookupOrCreateClass(String typeName, boolean isOopType, 630 boolean isIntegerType, boolean isUnsigned) { 631 BasicType type = (BasicType) lookupType(typeName, false); 632 if (type == null) { 633 // Create a new type 634 type = createBasicType(typeName, isOopType, isIntegerType, isUnsigned); 635 } 636 return type; 637 } 638 639 /** Creates a new BasicType, initializes its size to -1 so we can 640 test to ensure that all types' sizes are initialized by VMTypes, 641 and adds it to the database. Takes care of initializing integer 642 and oop types properly. */ createBasicType(String typeName, boolean isOopType, boolean isIntegerType, boolean isUnsigned)643 private BasicType createBasicType(String typeName, boolean isOopType, 644 boolean isIntegerType, boolean isUnsigned) { 645 646 BasicType type = null; 647 648 if (isIntegerType) { 649 type = new BasicCIntegerType(this, typeName, isUnsigned); 650 } else { 651 if (typeNameIsPointerType(typeName)) { 652 type = recursiveCreateBasicPointerType(typeName); 653 } else { 654 type = new BasicType(this, typeName); 655 } 656 657 if (isOopType) { 658 type.setIsOopType(true); 659 } 660 } 661 662 type.setSize(UNINITIALIZED_SIZE); 663 addType(type); 664 return type; 665 } 666 667 /** Recursively creates a PointerType from the string representation 668 of the type's name. Note that this currently needs some 669 workarounds due to incomplete information in the VMStructs 670 database. */ recursiveCreateBasicPointerType(String typeName)671 private BasicPointerType recursiveCreateBasicPointerType(String typeName) { 672 BasicPointerType result = (BasicPointerType)super.lookupType(typeName, false); 673 if (result != null) { 674 return result; 675 } 676 String targetTypeName = typeName.substring(0, typeName.lastIndexOf('*')).trim(); 677 Type targetType = null; 678 if (typeNameIsPointerType(targetTypeName)) { 679 targetType = lookupType(targetTypeName, false); 680 if (targetType == null) { 681 targetType = recursiveCreateBasicPointerType(targetTypeName); 682 } 683 } else { 684 targetType = lookupType(targetTypeName, false); 685 if (targetType == null) { 686 // Workaround for missing C integer types in database. 687 // Also looks like we can't throw an exception for other 688 // missing target types because there are some in old 689 // VMStructs tables that didn't have the target type declared. 690 // For this case, we create basic types that never get filled 691 // in. 692 693 if (targetTypeName.equals("char") || 694 targetTypeName.equals("const char")) { 695 // We don't have a representation of const-ness of C types in the SA 696 BasicType basicTargetType = createBasicType(targetTypeName, false, true, false); 697 basicTargetType.setSize(1); 698 targetType = basicTargetType; 699 } else if (targetTypeName.equals("u_char")) { 700 BasicType basicTargetType = createBasicType(targetTypeName, false, true, true); 701 basicTargetType.setSize(1); 702 targetType = basicTargetType; 703 } else { 704 if (DEBUG) { 705 System.err.println("WARNING: missing target type \"" + targetTypeName + "\" for pointer type \"" + typeName + "\""); 706 } 707 targetType = createBasicType(targetTypeName, false, false, false); 708 } 709 } 710 } 711 result = new BasicPointerType(this, typeName, targetType); 712 if (pointerSize == UNINITIALIZED_SIZE && !typeName.equals("void*")) { 713 // void* must be declared early so that other pointer types can use that to set their size. 714 throw new InternalError("void* type hasn't been seen when parsing " + typeName); 715 } 716 result.setSize(pointerSize); 717 addType(result); 718 return result; 719 } 720 typeNameIsPointerType(String typeName)721 private boolean typeNameIsPointerType(String typeName) { 722 int i = typeName.length() - 1; 723 while (i >= 0 && Character.isWhitespace(typeName.charAt(i))) { 724 --i; 725 } 726 if (i >= 0 && typeName.charAt(i) == '*') { 727 return true; 728 } 729 return false; 730 } 731 createType(String typeName, String superclassName, boolean isOopType, boolean isIntegerType, boolean isUnsigned, long size)732 public void createType(String typeName, String superclassName, 733 boolean isOopType, boolean isIntegerType, 734 boolean isUnsigned, long size) { 735 // See whether we have a superclass 736 BasicType superclass = null; 737 if (superclassName != null) { 738 // Fetch or create it (FIXME: would get oop types wrong if 739 // they had a hierarchy; consider using lookupOrFail) 740 superclass = lookupOrCreateClass(superclassName, false, false, false); 741 } 742 743 // Lookup or create the current type 744 BasicType curType = lookupOrCreateClass(typeName, isOopType, isIntegerType, isUnsigned); 745 // Set superclass and/or ensure it's correct 746 if (superclass != null) { 747 if (curType.getSuperclass() == null) { 748 // Set the superclass in the current type 749 curType.setSuperclass(superclass); 750 } 751 752 if (curType.getSuperclass() != superclass) { 753 throw new RuntimeException("Error: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " + 754 "had its superclass redefined (old was " + curType.getSuperclass().getName() + ", new is " + 755 superclass.getName() + ")."); 756 } 757 } 758 759 // Classes are created with a size of UNINITIALIZED_SIZE. 760 // Set size if necessary. 761 if (curType.getSize() == UNINITIALIZED_SIZE || curType.getSize() == 0) { 762 curType.setSize(size); 763 } else { 764 if (curType.getSize() != size) { 765 throw new RuntimeException("Error: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " + 766 "had its size redefined (old was " + curType.getSize() + ", new is " + size + ")."); 767 } 768 769 if (!typeNameIsPointerType(typeName)) { 770 System.err.println("Warning: the type \"" + typeName + "\" (declared in the remote VM in VMStructs::localHotSpotVMTypes) " + 771 "had its size declared as " + size + " twice. Continuing."); 772 duplicateDefCount++; 773 } 774 } 775 776 } 777 778 /** "Virtual constructor" for fields based on type */ createField(BasicType containingType, String name, Type type, boolean isStatic, long offset, Address staticFieldAddress)779 public void createField(BasicType containingType, 780 String name, Type type, boolean isStatic, 781 long offset, Address staticFieldAddress) { 782 // Add field to containing type 783 containingType.addField(internalCreateField(containingType, name, type, isStatic, offset, staticFieldAddress)); 784 } 785 internalCreateField(BasicType containingType, String name, Type type, boolean isStatic, long offset, Address staticFieldAddress)786 Field internalCreateField(BasicType containingType, 787 String name, Type type, boolean isStatic, 788 long offset, Address staticFieldAddress) { 789 // "Virtual constructor" based on type 790 if (type.isOopType()) { 791 return new BasicOopField(this, containingType, name, type, 792 isStatic, offset, staticFieldAddress); 793 } 794 795 if (type instanceof CIntegerType) { 796 return new BasicCIntegerField(this, containingType, name, type, 797 isStatic, offset, staticFieldAddress); 798 } 799 800 if (type.equals(getJBooleanType())) { 801 return new BasicJBooleanField(this, containingType, name, type, 802 isStatic, offset, staticFieldAddress); 803 } 804 805 if (type.equals(getJByteType())) { 806 return new BasicJByteField(this, containingType, name, type, 807 isStatic, offset, staticFieldAddress); 808 } 809 810 if (type.equals(getJCharType())) { 811 return new BasicJCharField(this, containingType, name, type, 812 isStatic, offset, staticFieldAddress); 813 } 814 815 if (type.equals(getJDoubleType())) { 816 return new BasicJDoubleField(this, containingType, name, type, 817 isStatic, offset, staticFieldAddress); 818 } 819 820 if (type.equals(getJFloatType())) { 821 return new BasicJFloatField(this, containingType, name, type, 822 isStatic, offset, staticFieldAddress); 823 } 824 825 if (type.equals(getJIntType())) { 826 return new BasicJIntField(this, containingType, name, type, 827 isStatic, offset, staticFieldAddress); 828 } 829 830 if (type.equals(getJLongType())) { 831 return new BasicJLongField(this, containingType, name, type, 832 isStatic, offset, staticFieldAddress); 833 } 834 835 if (type.equals(getJShortType())) { 836 return new BasicJShortField(this, containingType, name, type, 837 isStatic, offset, staticFieldAddress); 838 } 839 840 // Unknown ("opaque") type. Instantiate ordinary Field. 841 return new BasicField(this, containingType, name, type, 842 isStatic, offset, staticFieldAddress); 843 } 844 845 // For debugging dumpMemory(Address addr, int len)846 private void dumpMemory(Address addr, int len) { 847 int i = 0; 848 while (i < len) { 849 System.err.print(addr.addOffsetTo(i) + ":"); 850 for (int j = 0; j < 8 && i < len; i++, j++) { 851 String s = Long.toHexString(addr.getCIntegerAt(i, 1, true)); 852 System.err.print(" 0x"); 853 for (int k = 0; k < 2 - s.length(); k++) { 854 System.err.print("0"); 855 } 856 System.err.print(s); 857 } 858 System.err.println(); 859 } 860 } 861 } 862