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 
  74   public BasicTypeDataBase(MachineDescription machDesc, VtblAccess vtblAccess) {
  75     this.machDesc   = machDesc;
  76     this.vtblAccess = vtblAccess;
  77   }
  78 
  79   public Type lookupType(String cTypeName) {
  80     return lookupType(cTypeName, true);
  81   }
  82 
  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 
  91   public Integer lookupIntConstant(String constantName) {
  92     return lookupIntConstant(constantName, true);
  93   }
  94 
  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 
 105   public Long lookupLongConstant(String constantName) {
 106     return lookupLongConstant(constantName, true);
 107   }
 108 
 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 
 119   public Type getJBooleanType() {
 120     return jbooleanType;
 121   }
 122 
 123   public Type getJByteType() {
 124     return jbyteType;
 125   }
 126 
 127   public Type getJCharType() {
 128     return jcharType;
 129   }
 130 
 131   public Type getJDoubleType() {
 132     return jdoubleType;
 133   }
 134 
 135   public Type getJFloatType() {
 136     return jfloatType;
 137   }
 138 
 139   public Type getJIntType() {
 140     return jintType;
 141   }
 142 
 143   public Type getJLongType() {
 144     return jlongType;
 145   }
 146 
 147   public Type getJShortType() {
 148     return jshortType;
 149   }
 150 
 151   public long getAddressSize() {
 152     return machDesc.getAddressSize();
 153   }
 154 
 155   public long getOopSize() {
 156     return VM.getVM().getOopSize();
 157   }
 158 
 159   HashMap typeToVtbl = new HashMap();
 160 
 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 
 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 SparcWorks 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 SparcWorks 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 
 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) == true) {
 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 
 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 
 364   public long cIntegerTypeMaxValue(long sizeInBytes, boolean isUnsigned) {
 365     return machDesc.cIntegerTypeMaxValue(sizeInBytes, isUnsigned);
 366   }
 367 
 368   public long cIntegerTypeMinValue(long sizeInBytes, boolean isUnsigned) {
 369     return machDesc.cIntegerTypeMinValue(sizeInBytes, isUnsigned);
 370   }
 371 
 372   public Iterator getTypes() {
 373     return nameToTypeMap.values().iterator();
 374   }
 375 
 376   public Iterator getIntConstants() {
 377     return nameToIntConstantMap.keySet().iterator();
 378   }
 379 
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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 */
 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. */
 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. */
 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. */
 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. */
 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. */
 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. */
 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 }