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.types.basic; 26 27 import java.util.HashMap; 28 import java.util.Iterator; 29 import java.util.Map; 30 31 import sun.jvm.hotspot.debugger.Address; 32 import sun.jvm.hotspot.debugger.MachineDescription; 33 import sun.jvm.hotspot.runtime.VM; 34 import sun.jvm.hotspot.types.Type; 35 import sun.jvm.hotspot.types.TypeDataBase; 36 import sun.jvm.hotspot.memory.FileMapInfo; 37 38 /** <P> This is a basic implementation of the TypeDataBase interface. 39 It allows an external type database builder to add types to be 40 consumed by a client through the Type interfaces. It has no 41 knowledge of symbol lookup; for example, the builder is 42 responsible for providing the addresses of static fields. </P> 43 44 <P> Among other things, the database builder is responsible for 45 providing the Types for the Java primitive types, as well as their 46 sizes. </P> 47 */ 48 49 public class BasicTypeDataBase implements TypeDataBase { 50 private MachineDescription machDesc; 51 private VtblAccess vtblAccess; 52 /** Maps strings to Type objects. This does not contain the primitive types. */ 53 private Map nameToTypeMap = new HashMap(); 54 /** Maps strings to Integers, used for enums, etc. */ 55 private Map nameToIntConstantMap = new HashMap(); 56 /** Maps strings to Longs, used for 32/64-bit constants, etc. */ 57 private Map nameToLongConstantMap = new HashMap(); 58 /** Primitive types. */ 59 private Type jbooleanType; 60 private Type jbyteType; 61 private Type jcharType; 62 private Type jdoubleType; 63 private Type jfloatType; 64 private Type jintType; 65 private Type jlongType; 66 private Type jshortType; 67 68 /** For debugging */ 69 private static final boolean DEBUG; 70 static { 71 DEBUG = System.getProperty("sun.jvm.hotspot.types.basic.BasicTypeDataBase.DEBUG") != null; 72 } 73 BasicTypeDataBase(MachineDescription machDesc, VtblAccess vtblAccess)74 public BasicTypeDataBase(MachineDescription machDesc, VtblAccess vtblAccess) { 75 this.machDesc = machDesc; 76 this.vtblAccess = vtblAccess; 77 } 78 lookupType(String cTypeName)79 public Type lookupType(String cTypeName) { 80 return lookupType(cTypeName, true); 81 } 82 lookupType(String cTypeName, boolean throwException)83 public Type lookupType(String cTypeName, boolean throwException) { 84 Type type = (Type) nameToTypeMap.get(cTypeName); 85 if (type == null && throwException) { 86 throw new RuntimeException("No type named \"" + cTypeName + "\" in database"); 87 } 88 return type; 89 } 90 lookupIntConstant(String constantName)91 public Integer lookupIntConstant(String constantName) { 92 return lookupIntConstant(constantName, true); 93 } 94 lookupIntConstant(String constantName, boolean throwException)95 public Integer lookupIntConstant(String constantName, boolean throwException) { 96 Integer i = (Integer) nameToIntConstantMap.get(constantName); 97 if (i == null) { 98 if (throwException) { 99 throw new RuntimeException("No integer constant named \"" + constantName + "\" present in type database"); 100 } 101 } 102 return i; 103 } 104 lookupLongConstant(String constantName)105 public Long lookupLongConstant(String constantName) { 106 return lookupLongConstant(constantName, true); 107 } 108 lookupLongConstant(String constantName, boolean throwException)109 public Long lookupLongConstant(String constantName, boolean throwException) { 110 Long i = (Long) nameToLongConstantMap.get(constantName); 111 if (i == null) { 112 if (throwException) { 113 throw new RuntimeException("No long constant named \"" + constantName + "\" present in type database"); 114 } 115 } 116 return i; 117 } 118 getJBooleanType()119 public Type getJBooleanType() { 120 return jbooleanType; 121 } 122 getJByteType()123 public Type getJByteType() { 124 return jbyteType; 125 } 126 getJCharType()127 public Type getJCharType() { 128 return jcharType; 129 } 130 getJDoubleType()131 public Type getJDoubleType() { 132 return jdoubleType; 133 } 134 getJFloatType()135 public Type getJFloatType() { 136 return jfloatType; 137 } 138 getJIntType()139 public Type getJIntType() { 140 return jintType; 141 } 142 getJLongType()143 public Type getJLongType() { 144 return jlongType; 145 } 146 getJShortType()147 public Type getJShortType() { 148 return jshortType; 149 } 150 getAddressSize()151 public long getAddressSize() { 152 return machDesc.getAddressSize(); 153 } 154 getOopSize()155 public long getOopSize() { 156 return VM.getVM().getOopSize(); 157 } 158 159 HashMap typeToVtbl = new HashMap(); 160 vtblForType(Type type)161 private Address vtblForType(Type type) { 162 Address vtblAddr = (Address)typeToVtbl.get(type); 163 if (vtblAddr == null) { 164 vtblAddr = vtblAccess.getVtblForType(type); 165 if (vtblAddr != null) { 166 typeToVtbl.put(type, vtblAddr); 167 } 168 } 169 return vtblAddr; 170 } 171 addressTypeIsEqualToType(Address addr, Type type)172 public boolean addressTypeIsEqualToType(Address addr, Type type) { 173 if (addr == null) { 174 return false; 175 } 176 177 // This implementation should be suitably platform-independent; we 178 // search nearby memory for the vtbl value of the given type. 179 180 Address vtblAddr = vtblForType(type); 181 182 if (vtblAddr == null) { 183 // Type was not polymorphic, or an error occurred during lookup 184 if (DEBUG) { 185 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: vtblAddr == null"); 186 } 187 188 return false; 189 } 190 191 // The first implementation searched three locations for this vtbl 192 // value; scanning through the entire object was considered, but 193 // we thought we knew where we were looking, and looking only in 194 // these specific locations should reduce the probability of 195 // mistaking random bits as a pointer (although, realistically 196 // speaking, the likelihood of finding a match between the bit 197 // pattern of, for example, a double and the vtbl is vanishingly 198 // small.) 199 // 1. The first word of the object (should handle MSVC++ as 200 // well as the solstudio compilers with compatibility set to 201 // v5.0 or greater) 202 // 2. and 3. The last two Address-aligned words of the part of 203 // the object defined by its topmost polymorphic superclass. 204 // This should handle the solstudio compilers, v4.2 or 205 // earlier, as well as any other compilers which place the vptr 206 // at the end of the user-defined fields of the first base 207 // class with virtual functions. 208 // 209 // Unfortunately this algorithm did not work properly for the 210 // specific case of the ThreadShadow/Thread inheritance situation, 211 // because the Solaris compiler seems to cleverly eliminate the 212 // vtbl for ThreadShadow since the only virtual is empty. (We 213 // should get rid of the ThreadShadow and fix the include 214 // databases, but need to postpone this for the present.) The 215 // current solution performs the three-location check for this 216 // class and all of its known superclasses rather than just the 217 // topmost polymorphic one. 218 219 Type curType = type; 220 221 try { 222 while (curType != null) { 223 // Using the size information we have for this type, check the 224 // three locations described above. 225 226 // (1) 227 if (vtblAddr.equals(addr.getAddressAt(0))) { 228 return true; 229 } 230 231 // (2) 232 long offset = curType.getSize(); 233 // I don't think this should be misaligned under any 234 // circumstances, but I'm not sure (FIXME: also not sure which 235 // way to go here, up or down -- assuming down) 236 offset -= (offset % getAddressSize()); 237 if (offset <= 0) { 238 return false; 239 } 240 if (vtblAddr.equals(addr.getAddressAt(offset))) { 241 return true; 242 } 243 offset -= getAddressSize(); 244 if (offset <= 0) { 245 return false; 246 } 247 if (vtblAddr.equals(addr.getAddressAt(offset))) { 248 return true; 249 } 250 251 curType = curType.getSuperclass(); 252 } 253 } 254 catch (Exception e) { 255 // Any UnmappedAddressExceptions, etc. are a good indication 256 // that the pointer is not of the specified type 257 if (DEBUG) { 258 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: exception occurred during lookup:"); 259 e.printStackTrace(); 260 } 261 262 return false; 263 } 264 265 if (DEBUG) { 266 System.err.println("BasicTypeDataBase.addressTypeIsEqualToType: all vptr tests failed for type " + 267 type.getName()); 268 } 269 270 return false; 271 } 272 findDynamicTypeForAddress(Address addr, Type baseType)273 public Type findDynamicTypeForAddress(Address addr, Type baseType) { 274 // This implementation should be suitably platform-independent; we 275 // search nearby memory for the vtbl value of the given type. 276 277 if (vtblForType(baseType) == null) { 278 // Type was not polymorphic which is an error of some sort 279 throw new InternalError(baseType + " does not appear to be polymorphic"); 280 } 281 282 // This is a more restricted version of guessTypeForAddress since 283 // that function has some limitations since it doesn't really know 284 // where in the hierarchy a virtual type starts and just poking 285 // around in memory is likely to trip over some vtable address, 286 // resulting in false positives. Eventually all uses should 287 // switch to this logic but in the interests of stability it will 288 // be separate for the moment. 289 290 // Assuming that the base type is truly the first polymorphic type 291 // then the vtbl for all subclasss should be at several defined 292 // locations so only those locations will be checked. It's also 293 // required that the caller knows that the static type is at least 294 // baseType. See the notes in guessTypeForAddress for the logic of 295 // the locations searched. 296 297 Address loc1 = addr.getAddressAt(0); 298 299 if (VM.getVM().isSharingEnabled()) { 300 // Check if the value falls in the _md_region 301 FileMapInfo cdsFileMapInfo = VM.getVM().getFileMapInfo(); 302 if (cdsFileMapInfo.inCopiedVtableSpace(loc1)) { 303 return cdsFileMapInfo.getTypeForVptrAddress(loc1); 304 } 305 } 306 307 Address loc2 = null; 308 Address loc3 = null; 309 long offset2 = baseType.getSize(); 310 // I don't think this should be misaligned under any 311 // circumstances, but I'm not sure (FIXME: also not sure which 312 // way to go here, up or down -- assuming down) 313 offset2 = offset2 - (offset2 % getAddressSize()) - getAddressSize(); 314 if (offset2 > 0) { 315 loc2 = addr.getAddressAt(offset2); 316 } 317 long offset3 = offset2 - getAddressSize(); 318 if (offset3 > 0) { 319 loc3 = addr.getAddressAt(offset3); 320 } 321 322 Type loc2Match = null; 323 Type loc3Match = null; 324 for (Iterator iter = getTypes(); iter.hasNext(); ) { 325 Type type = (Type) iter.next(); 326 Type superClass = type; 327 while (superClass != baseType && superClass != null) { 328 superClass = superClass.getSuperclass(); 329 } 330 if (superClass == null) continue; 331 Address vtblAddr = vtblForType(type); 332 if (vtblAddr == null) { 333 // This occurs sometimes for intermediate types that are never 334 // instantiated. 335 if (DEBUG) { 336 System.err.println("null vtbl for " + type); 337 } 338 continue; 339 } 340 // Prefer loc1 match 341 if (vtblAddr.equals(loc1)) return type; 342 if (loc2 != null && loc2Match == null && vtblAddr.equals(loc2)) { 343 loc2Match = type; 344 } 345 if (loc3 != null && loc3Match == null && vtblAddr.equals(loc3)) { 346 loc3Match = type; 347 } 348 } 349 if (loc2Match != null) return loc2Match; 350 if (loc3Match != null) return loc3Match; 351 return null; 352 } 353 guessTypeForAddress(Address addr)354 public Type guessTypeForAddress(Address addr) { 355 for (Iterator iter = getTypes(); iter.hasNext(); ) { 356 Type t = (Type) iter.next(); 357 if (addressTypeIsEqualToType(addr, t)) { 358 return t; 359 } 360 } 361 return null; 362 } 363 cIntegerTypeMaxValue(long sizeInBytes, boolean isUnsigned)364 public long cIntegerTypeMaxValue(long sizeInBytes, boolean isUnsigned) { 365 return machDesc.cIntegerTypeMaxValue(sizeInBytes, isUnsigned); 366 } 367 cIntegerTypeMinValue(long sizeInBytes, boolean isUnsigned)368 public long cIntegerTypeMinValue(long sizeInBytes, boolean isUnsigned) { 369 return machDesc.cIntegerTypeMinValue(sizeInBytes, isUnsigned); 370 } 371 getTypes()372 public Iterator getTypes() { 373 return nameToTypeMap.values().iterator(); 374 } 375 getIntConstants()376 public Iterator getIntConstants() { 377 return nameToIntConstantMap.keySet().iterator(); 378 } 379 getLongConstants()380 public Iterator getLongConstants() { 381 return nameToLongConstantMap.keySet().iterator(); 382 } 383 384 //-------------------------------------------------------------------------------- 385 // Public routines only for use by the database builder 386 // 387 388 /** This method should only be called by the builder of the 389 TypeDataBase and at most once */ setJBooleanType(Type type)390 public void setJBooleanType(Type type) { 391 jbooleanType = type; 392 } 393 394 /** This method should only be called by the builder of the 395 TypeDataBase and at most once */ setJByteType(Type type)396 public void setJByteType(Type type) { 397 jbyteType = type; 398 } 399 400 /** This method should only be called by the builder of the 401 TypeDataBase and at most once */ setJCharType(Type type)402 public void setJCharType(Type type) { 403 jcharType = type; 404 } 405 406 /** This method should only be called by the builder of the 407 TypeDataBase and at most once */ setJDoubleType(Type type)408 public void setJDoubleType(Type type) { 409 jdoubleType = type; 410 } 411 412 /** This method should only be called by the builder of the 413 TypeDataBase and at most once */ setJFloatType(Type type)414 public void setJFloatType(Type type) { 415 jfloatType = type; 416 } 417 418 /** This method should only be called by the builder of the 419 TypeDataBase and at most once */ setJIntType(Type type)420 public void setJIntType(Type type) { 421 jintType = type; 422 } 423 424 /** This method should only be called by the builder of the 425 TypeDataBase and at most once */ setJLongType(Type type)426 public void setJLongType(Type type) { 427 jlongType = type; 428 } 429 430 /** This method should only be called by the builder of the 431 TypeDataBase and at most once */ setJShortType(Type type)432 public void setJShortType(Type type) { 433 jshortType = type; 434 } 435 436 /** This method should only be used by the builder of the 437 TypeDataBase. Throws a RuntimeException if a class with this 438 name was already present. */ addType(Type type)439 public void addType(Type type) { 440 if (nameToTypeMap.get(type.getName()) != null) { 441 throw new RuntimeException("type of name \"" + type.getName() + "\" already present"); 442 } 443 444 nameToTypeMap.put(type.getName(), type); 445 } 446 447 /** This method should only be used by the builder of the 448 TypeDataBase. Throws a RuntimeException if this class was not 449 present. */ removeType(Type type)450 public void removeType(Type type) { 451 Type curType = (Type) nameToTypeMap.get(type.getName()); 452 if (curType == null) { 453 throw new RuntimeException("type of name \"" + type.getName() + "\" not present"); 454 } 455 456 if (!curType.equals(type)) { 457 throw new RuntimeException("a different type of name \"" + type.getName() + "\" was present"); 458 } 459 460 nameToTypeMap.remove(type.getName()); 461 } 462 463 /** This method should only be used by the builder of the 464 TypeDataBase. Throws a RuntimeException if an integer constant 465 with this name was already present. */ addIntConstant(String name, int value)466 public void addIntConstant(String name, int value) { 467 if (nameToIntConstantMap.get(name) != null) { 468 throw new RuntimeException("int constant of name \"" + name + "\" already present"); 469 } 470 471 nameToIntConstantMap.put(name, new Integer(value)); 472 } 473 474 /** This method should only be used by the builder of the 475 TypeDataBase. Throws a RuntimeException if an integer constant 476 with this name was not present. */ removeIntConstant(String name)477 public void removeIntConstant(String name) { 478 Integer curConstant = (Integer) nameToIntConstantMap.get(name); 479 if (curConstant == null) { 480 throw new RuntimeException("int constant of name \"" + name + "\" not present"); 481 } 482 483 nameToIntConstantMap.remove(name); 484 } 485 486 /** This method should only be used by the builder of the 487 TypeDataBase. Throws a RuntimeException if a long constant with 488 this name was already present. */ addLongConstant(String name, long value)489 public void addLongConstant(String name, long value) { 490 if (nameToLongConstantMap.get(name) != null) { 491 throw new RuntimeException("long constant of name \"" + name + "\" already present"); 492 } 493 494 nameToLongConstantMap.put(name, new Long(value)); 495 } 496 497 /** This method should only be used by the builder of the 498 TypeDataBase. Throws a RuntimeException if a long constant with 499 this name was not present. */ removeLongConstant(String name)500 public void removeLongConstant(String name) { 501 Long curConstant = (Long) nameToLongConstantMap.get(name); 502 if (curConstant == null) { 503 throw new RuntimeException("long constant of name \"" + name + "\" not present"); 504 } 505 506 nameToLongConstantMap.remove(name); 507 } 508 } 509