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