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