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