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