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 }