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