1 /*
  2  * Copyright (c) 2018, 2023, 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.memory;
 26 
 27 import java.util.*;
 28 import sun.jvm.hotspot.debugger.Address;
 29 import sun.jvm.hotspot.runtime.VM;
 30 import sun.jvm.hotspot.runtime.VMObject;
 31 import sun.jvm.hotspot.runtime.VMObjectFactory;
 32 import sun.jvm.hotspot.types.*;
 33 import sun.jvm.hotspot.utilities.Observable;
 34 import sun.jvm.hotspot.utilities.Observer;
 35 
 36 public class FileMapInfo {
 37   private static FileMapHeader headerObj;
 38 
 39   // Fields for handling the copied C++ vtables
 40   private static Address rwRegionBaseAddress;
 41   private static Address rwRegionEndAddress;
 42   private static Address vtablesIndex;
 43 
 44   // HashMap created by mapping the vTable addresses in the rw region with
 45   // the corresponding metadata type.
 46   private static Map<Address, Type> vTableTypeMap;
 47 
 48   private static Type metadataTypeArray[];
 49 
 50   static {
 51     VM.registerVMInitializedObserver(new Observer() {
 52         public void update(Observable o, Object data) {
 53           initialize(VM.getVM().getTypeDataBase());
 54         }
 55       });
 56   }
 57 
 58   static Address getStatic_AddressField(Type type, String fieldName) {
 59     AddressField field = type.getAddressField(fieldName);
 60     return field.getValue();
 61   }
 62 
 63   static Address get_AddressField(Type type, Address instance, String fieldName) {
 64     AddressField field = type.getAddressField(fieldName);
 65     return field.getValue(instance);
 66   }
 67 
 68   static long get_CIntegerField(Type type, Address instance, String fieldName) {
 69     CIntegerField field = type.getCIntegerField(fieldName);
 70     return field.getValue(instance);
 71   }
 72 
 73   // C equivalent:   return &header->_regions[index];
 74   static Address get_CDSFileMapRegion(Type FileMapHeader_type, Address header, int index) {
 75     AddressField regionsField = FileMapHeader_type.getAddressField("_regions[0]");
 76 
 77     // size_t offset = offsetof(FileMapHeader, _regions[0]);
 78     // CDSFileMapRegion* regions_0 = ((char*)header) + offset; // regions_0 = &header->_regions[index];
 79     // return ((char*)regions_0) + index * sizeof(CDSFileMapRegion);
 80     long offset = regionsField.getOffset();
 81     Address regions_0 = header.addOffsetTo(offset);
 82     return regions_0.addOffsetTo(index * regionsField.getSize());
 83   }
 84 
 85   private static void initialize(TypeDataBase db) {
 86     vTableTypeMap = null; // force vTableTypeMap to get re-initialized later
 87 
 88     Type FileMapInfo_type = db.lookupType("FileMapInfo");
 89     Type FileMapHeader_type = db.lookupType("FileMapHeader");
 90     Type CDSFileMapRegion_type = db.lookupType("CDSFileMapRegion");
 91 
 92     // FileMapInfo * info = FileMapInfo::_current_info;
 93     // FileMapHeader* header = info->_header
 94     Address info = getStatic_AddressField(FileMapInfo_type, "_current_info");
 95     Address header = get_AddressField(FileMapInfo_type, info, "_header");
 96     headerObj = VMObjectFactory.newObject(FileMapHeader.class, header);
 97 
 98     // char* mapped_base_address = header->_mapped_base_address
 99     // size_t cloned_vtable_offset = header->_cloned_vtable_offset
100     // CppVtableInfo** vtablesIndex = mapped_base_address + cloned_vtable_offset;
101     Address mapped_base_address = get_AddressField(FileMapHeader_type, header, "_mapped_base_address");
102     long cloned_vtable_offset = get_CIntegerField(FileMapHeader_type, header, "_cloned_vtables_offset");
103     vtablesIndex = mapped_base_address.addOffsetTo(cloned_vtable_offset);
104 
105     // CDSFileMapRegion* rw_region = &header->_region[rw];
106     // char* rwRegionBaseAddress = rw_region->_mapped_base;
107     // size_t used = rw_region->_used;
108     // char* rwRegionEndAddress = rwRegionBaseAddress + used;
109     Address rw_region = get_CDSFileMapRegion(FileMapHeader_type, header, 0);
110     rwRegionBaseAddress = get_AddressField(CDSFileMapRegion_type, rw_region, "_mapped_base");
111     long used = get_CIntegerField(CDSFileMapRegion_type, rw_region, "_used");
112     rwRegionEndAddress = rwRegionBaseAddress.addOffsetTo(used);
113 
114     populateMetadataTypeArray(db);
115   }
116 
117   private static void populateMetadataTypeArray(TypeDataBase db) {
118     metadataTypeArray = new Type[11];
119     // The order needs to match up with CPP_VTABLE_TYPES_DO in src/hotspot/share/cds/cppVtables.cpp
120     metadataTypeArray[0] = db.lookupType("ConstantPool");
121     metadataTypeArray[1] = db.lookupType("InstanceKlass");
122     metadataTypeArray[2] = db.lookupType("InstanceClassLoaderKlass");
123     metadataTypeArray[3] = db.lookupType("InstanceMirrorKlass");
124     metadataTypeArray[4] = db.lookupType("InstanceRefKlass");
125     metadataTypeArray[5] = db.lookupType("InstanceStackChunkKlass");
126     metadataTypeArray[6] = db.lookupType("Method");
127     metadataTypeArray[9] = db.lookupType("MethodData");
128     metadataTypeArray[8] = db.lookupType("MethodCounters");
129     metadataTypeArray[9] = db.lookupType("ObjArrayKlass");
130     metadataTypeArray[10] = db.lookupType("TypeArrayKlass");
131   }
132 
133   public FileMapHeader getHeader() {
134     return headerObj;
135   }
136 
137   public boolean inCopiedVtableSpace(Address vptrAddress) {
138     FileMapHeader fmHeader = getHeader();
139     return fmHeader.inCopiedVtableSpace(vptrAddress);
140   }
141 
142   public Type getTypeForVptrAddress(Address vptrAddress) {
143     if (vTableTypeMap == null) {
144       getHeader().createVtableTypeMapping();
145     }
146     return vTableTypeMap.get(vptrAddress);
147   }
148 
149 
150   //------------------------------------------------------------------------------------------
151 
152   public static class FileMapHeader extends VMObject {
153 
154     public FileMapHeader(Address addr) {
155       super(addr);
156     }
157 
158     public boolean inCopiedVtableSpace(Address vptrAddress) {
159       if (vptrAddress == null) {
160         return false;
161       }
162       if (vptrAddress.greaterThan(rwRegionBaseAddress) &&
163           vptrAddress.lessThanOrEqual(rwRegionEndAddress)) {
164         return true;
165       }
166       return false;
167     }
168 
169     public void createVtableTypeMapping() {
170       vTableTypeMap = new HashMap<Address, Type>();
171       long addressSize = VM.getVM().getAddressSize();
172 
173       // vtablesIndex points to this:
174       //     class CppVtableInfo {
175       //         intptr_t _vtable_size;
176       //         intptr_t _cloned_vtable[1];
177       //         ...
178       //     };
179       //     CppVtableInfo** CppVtables::_index;
180       // This is the index of all the cloned vtables. E.g., for
181       //     ConstantPool* cp = ....; // an archived constant pool
182       //     InstanceKlass* ik = ....;// an archived class
183       // the following holds true:
184       //     &_index[ConstantPool_Kind]->_cloned_vtable[0]  == ((intptr_t**)cp)[0]
185       //     &_index[InstanceKlass_Kind]->_cloned_vtable[0] == ((intptr_t**)ik)[0]
186 
187       for (int i=0; i < metadataTypeArray.length; i++) {
188         Address vtableInfoAddress = vtablesIndex.getAddressAt(i * addressSize); // = _index[i]
189         Address vtableAddress = vtableInfoAddress.addOffsetTo(addressSize); // = &_index[i]->_cloned_vtable[0]
190         vTableTypeMap.put(vtableAddress, metadataTypeArray[i]);
191       }
192     }
193   }
194 }