--- old/src/hotspot/share/memory/filemap.hpp 2018-04-25 08:29:39.349931000 +0530 +++ new/src/hotspot/share/memory/filemap.hpp 2018-04-25 08:29:39.137931000 +0530 @@ -75,6 +75,7 @@ class FileMapInfo : public CHeapObj { private: friend class ManifestStream; + friend class VMStructs; enum { _invalid_version = -1, _current_version = 3 --- old/src/hotspot/share/runtime/vmStructs.cpp 2018-04-25 08:29:39.917931000 +0530 +++ new/src/hotspot/share/runtime/vmStructs.cpp 2018-04-25 08:29:39.745931000 +0530 @@ -56,6 +56,7 @@ #include "memory/referenceType.hpp" #include "memory/universe.hpp" #include "memory/virtualspace.hpp" +#include "memory/filemap.hpp" #include "oops/array.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" @@ -1118,6 +1119,16 @@ static_field(java_lang_Class, _oop_size_offset, int) \ static_field(java_lang_Class, _static_oop_field_count_offset, int) \ \ + /********************************************/ \ + /* FileMapInfo fields (CDS archive related) */ \ + /********************************************/ \ + \ + nonstatic_field(FileMapInfo, _header, FileMapInfo::FileMapHeader*) \ + static_field(FileMapInfo, _current_info, FileMapInfo*) \ + nonstatic_field(FileMapInfo::FileMapHeader, _space[0], FileMapInfo::FileMapHeader::space_info)\ + nonstatic_field(FileMapInfo::FileMapHeader::space_info, _addr._base, char*) \ + nonstatic_field(FileMapInfo::FileMapHeader::space_info, _used, size_t) \ + \ /******************/ \ /* VMError fields */ \ /******************/ \ @@ -1442,7 +1453,7 @@ declare_type(SafepointBlob, SingletonBlob) \ declare_type(DeoptimizationBlob, SingletonBlob) \ declare_c2_type(ExceptionBlob, SingletonBlob) \ - declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ + declare_c2_type(UncommonTrapBlob, RuntimeBlob) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -1997,6 +2008,10 @@ declare_toplevel_type(vframeArrayElement) \ declare_toplevel_type(Annotations*) \ declare_type(OopMapValue, StackObj) \ + declare_type(FileMapInfo, CHeapObj) \ + declare_type(FileMapInfo::FileMapHeaderBase, CHeapObj) \ + declare_type(FileMapInfo::FileMapHeader, FileMapInfo::FileMapHeaderBase)\ + declare_toplevel_type(FileMapInfo::FileMapHeader::space_info) \ \ /************/ \ /* GC types */ \ --- old/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c 2018-04-25 08:29:40.549931000 +0530 +++ new/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c 2018-04-25 08:29:40.365931000 +0530 @@ -212,29 +212,51 @@ // mapped. This structure gets written to a file. It is not a class, // so that the compilers don't add any compiler-private data to it. -#define NUM_SHARED_MAPS 4 +#define NUM_SHARED_MAPS 9 // Refer to FileMapInfo::_current_version in filemap.hpp -#define CURRENT_ARCHIVE_VERSION 1 +#define CURRENT_ARCHIVE_VERSION 3 + +typedef unsigned char* address; +typedef uintptr_t uintx; +typedef intptr_t intx; struct FileMapHeader { - int _magic; // identify file type. - int _version; // (from enum, above.) - size_t _alignment; // how shared archive should be aligned + int _magic; // identify file type. + int _crc; // header crc checksum. + int _version; // (from enum, above.) + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes + address _narrow_oop_base; // compressed oop encoding base + int _narrow_oop_shift; // compressed oop encoding shift + bool _compact_strings; // value of CompactStrings + uintx _max_heap_size; // java max heap size during dumping + int _narrow_oop_mode; // compressed oop encoding mode + int _narrow_klass_shift; // save narrow klass base and shift + address _narrow_klass_base; + char* _misc_data_patching_start; + char* _read_only_tables_start; + address _cds_i2i_entry_code_buffers; + size_t _cds_i2i_entry_code_buffers_size; + size_t _core_spaces_size; // number of bytes allocated by the core spaces + // (mc, md, ro, rw and od). - struct space_info { - int _file_offset; // sizeof(this) rounded to vm page size - char* _base; // copy-on-write base address - size_t _capacity; // for validity checking - size_t _used; // for setting space top on read + struct space_info { + int _crc; // crc checksum of the current space + size_t _file_offset; // sizeof(this) rounded to vm page size + union { + char* _base; // copy-on-write base address + intx _offset; // offset from the compressed oop encoding base, only used + // by archive heap space + } _addr; + size_t _used; // for setting space top on read // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with // the C type matching the C++ bool type on any given platform. // We assume the corresponding C type is char but licensees // may need to adjust the type of these fields. - char _read_only; // read only space? - char _allow_exec; // executable code in space? - + char _read_only; // read only space? + char _allow_exec; // executable code in space? } _space[NUM_SHARED_MAPS]; // Ignore the rest of the FileMapHeader. We don't need those fields here. @@ -381,7 +403,7 @@ // add read-only maps from classes.jsa to the list of maps for (m = 0; m < NUM_SHARED_MAPS; m++) { if (header._space[m]._read_only) { - base = (uintptr_t) header._space[m]._base; + base = (uintptr_t) header._space[m]._addr._base; // no need to worry about the fractional pages at-the-end. // possible fractional pages are handled by core_read_data. add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, --- old/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c 2018-04-25 08:29:41.145931000 +0530 +++ new/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c 2018-04-25 08:29:40.961931000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -213,29 +213,52 @@ // mapped. This structure gets written to a file. It is not a class, // so that the compilers don't add any compiler-private data to it. -#define NUM_SHARED_MAPS 4 +#define NUM_SHARED_MAPS 9 // Refer to FileMapInfo::_current_version in filemap.hpp -#define CURRENT_ARCHIVE_VERSION 1 +#define CURRENT_ARCHIVE_VERSION 3 + +typedef unsigned char* address; +typedef uintptr_t uintx; +typedef intptr_t intx; + struct FileMapHeader { - int _magic; // identify file type. - int _version; // (from enum, above.) - size_t _alignment; // how shared archive should be aligned + int _magic; // identify file type. + int _crc; // header crc checksum. + int _version; // (from enum, above.) + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes + address _narrow_oop_base; // compressed oop encoding base + int _narrow_oop_shift; // compressed oop encoding shift + bool _compact_strings; // value of CompactStrings + uintx _max_heap_size; // java max heap size during dumping + int _narrow_oop_mode; // compressed oop encoding mode + int _narrow_klass_shift; // save narrow klass base and shift + address _narrow_klass_base; + char* _misc_data_patching_start; + char* _read_only_tables_start; + address _cds_i2i_entry_code_buffers; + size_t _cds_i2i_entry_code_buffers_size; + size_t _core_spaces_size; // number of bytes allocated by the core spaces + // (mc, md, ro, rw and od). - struct space_info { - int _file_offset; // sizeof(this) rounded to vm page size - char* _base; // copy-on-write base address - size_t _capacity; // for validity checking - size_t _used; // for setting space top on read + struct space_info { + int _crc; // crc checksum of the current space + size_t _file_offset; // sizeof(this) rounded to vm page size + union { + char* _base; // copy-on-write base address + intx _offset; // offset from the compressed oop encoding base, only used + // by archive heap space + } _addr; + size_t _used; // for setting space top on read // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with // the C type matching the C++ bool type on any given platform. // We assume the corresponding C type is char but licensees // may need to adjust the type of these fields. - char _read_only; // read only space? - char _allow_exec; // executable code in space? - + char _read_only; // read only space? + char _allow_exec; // executable code in space? } _space[NUM_SHARED_MAPS]; // Ignore the rest of the FileMapHeader. We don't need those fields here. @@ -282,15 +305,14 @@ return true; } +// mangled name of Arguments::SharedArchivePath +#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" + #ifdef __APPLE__ #define USE_SHARED_SPACES_SYM "_UseSharedSpaces" -// mangled name of Arguments::SharedArchivePath -#define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE" #define LIBJVM_NAME "/libjvm.dylib" #else #define USE_SHARED_SPACES_SYM "UseSharedSpaces" -// mangled name of Arguments::SharedArchivePath -#define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE" #define LIBJVM_NAME "/libjvm.so" #endif // __APPLE_ @@ -387,7 +409,7 @@ // add read-only maps from classes.jsa to the list of maps for (m = 0; m < NUM_SHARED_MAPS; m++) { if (header._space[m]._read_only) { - base = (uintptr_t) header._space[m]._base; + base = (uintptr_t) header._space[m]._addr._base; // no need to worry about the fractional pages at-the-end. // possible fractional pages are handled by core_read_data. add_class_share_map_info(ph, (off_t) header._space[m]._file_offset, --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java 2018-04-25 08:29:41.937931000 +0530 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java 2018-04-25 08:29:41.693931000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,7 @@ private JNIHandles handles; private Interpreter interpreter; private StubRoutines stubRoutines; + private FileMapInfo fileMapInfo; private Bytes bytes; /** Flag indicating if JVMTI support is included in the build */ @@ -717,6 +718,16 @@ return vmregImpl; } + public FileMapInfo getFileMapInfo() { + if (!isSharingEnabled()) { + return null; + } + if (fileMapInfo == null) { + fileMapInfo = new FileMapInfo(); + } + return fileMapInfo; + } + public Bytes getBytes() { if (bytes == null) { bytes = new Bytes(debugger.getMachineDescription()); --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java 2018-04-25 08:29:42.625931000 +0530 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java 2018-04-25 08:29:42.457931000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; +import sun.jvm.hotspot.memory.FileMapInfo; /**

This is a basic implementation of the TypeDataBase interface. It allows an external type database builder to add types to be @@ -294,6 +295,15 @@ // the locations searched. Address loc1 = addr.getAddressAt(0); + + if (VM.getVM().isSharingEnabled()) { + // Check if the value falls in the _md_region + FileMapInfo cdsFileMapInfo = VM.getVM().getFileMapInfo(); + if (cdsFileMapInfo.inCopiedVtableSpace(loc1)) { + return cdsFileMapInfo.getTypeForVptrAddress(loc1); + } + } + Address loc2 = null; Address loc3 = null; long offset2 = baseType.getSize(); --- old/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp 2018-04-25 08:29:43.293931000 +0530 +++ new/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp 2018-04-25 08:29:43.069931000 +0530 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -496,29 +496,54 @@ // mapped. This structure gets written to a file. It is not a class, so // that the compilers don't add any compiler-private data to it. -const int NUM_SHARED_MAPS = 4; +const int NUM_SHARED_MAPS = 9; // Refer to FileMapInfo::_current_version in filemap.hpp -const int CURRENT_ARCHIVE_VERSION = 1; +const int CURRENT_ARCHIVE_VERSION = 3; -struct FileMapHeader { - int _magic; // identify file type. - int _version; // (from enum, above.) - size_t _alignment; // how shared archive should be aligned - - - struct space_info { - int _file_offset; // sizeof(this) rounded to vm page size - char* _base; // copy-on-write base address - size_t _capacity; // for validity checking - size_t _used; // for setting space top on read +typedef unsigned char* address; +typedef uintptr_t uintx; +typedef intptr_t intx; - bool _read_only; // read only space? - bool _allow_exec; // executable code in space? - - } _space[NUM_SHARED_MAPS]; +struct FileMapHeader { + int _magic; // identify file type. + int _crc; // header crc checksum. + int _version; // (from enum, above.) + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes + address _narrow_oop_base; // compressed oop encoding base + int _narrow_oop_shift; // compressed oop encoding shift + bool _compact_strings; // value of CompactStrings + uintx _max_heap_size; // java max heap size during dumping + int _narrow_oop_mode; // compressed oop encoding mode + int _narrow_klass_shift; // save narrow klass base and shift + address _narrow_klass_base; + char* _misc_data_patching_start; + char* _read_only_tables_start; + address _cds_i2i_entry_code_buffers; + size_t _cds_i2i_entry_code_buffers_size; + size_t _core_spaces_size; // number of bytes allocated by the core spaces + // (mc, md, ro, rw and od). + + + struct space_info { + int _crc; // crc checksum of the current space + size_t _file_offset; // sizeof(this) rounded to vm page size + union { + char* _base; // copy-on-write base address + intx _offset; // offset from the compressed oop encoding base, only used + // by archive heap space + } _addr; + size_t _used; // for setting space top on read + // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with + // the C type matching the C++ bool type on any given platform. + // We assume the corresponding C type is char but licensees + // may need to adjust the type of these fields. + char _read_only; // read only space? + char _allow_exec; // executable code in space? + } _space[NUM_SHARED_MAPS]; - // Ignore the rest of the FileMapHeader. We don't need those fields here. +// Ignore the rest of the FileMapHeader. We don't need those fields here. }; static bool @@ -677,7 +702,7 @@ if (_libsaproc_debug) { for (int m = 0; m < NUM_SHARED_MAPS; m++) { print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n", - pheader->_space[m]._file_offset, pheader->_space[m]._base, + pheader->_space[m]._file_offset, pheader->_space[m]._addr._base, pheader->_space[m]._used, pheader->_space[m]._read_only); } } @@ -1058,7 +1083,7 @@ print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address); struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID); - // walk through the shared mappings -- we just have 4 of them. + // walk through the shared mappings -- we just have 9 of them. // so, linear walking is okay. for (int m = 0; m < NUM_SHARED_MAPS; m++) { @@ -1066,7 +1091,7 @@ // and hence will be read by libproc. Besides, the file copy may be // stale because the process might have modified those pages. if (pheader->_space[m]._read_only) { - jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._base; + jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._addr._base; size_t usedSize = pheader->_space[m]._used; if (address >= baseAddress && address < (baseAddress + usedSize)) { // the given address falls in this shared heap area --- old/test/hotspot/jtreg/serviceability/sa/ClhsdbLauncher.java 2018-04-25 08:29:43.969931000 +0530 +++ new/test/hotspot/jtreg/serviceability/sa/ClhsdbLauncher.java 2018-04-25 08:29:43.781931000 +0530 @@ -29,6 +29,7 @@ import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.Platform; import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.JDKToolFinder; import jdk.test.lib.process.OutputAnalyzer; /** @@ -68,6 +69,27 @@ /** * + * Launches 'jhsdb clhsdb' and loads a core file. + * @param coreFileName - Name of the corefile to be loaded. + */ + private void loadCore(String coreFileName) + throws IOException { + + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + launcher.addToolArg("clhsdb"); + launcher.addToolArg("--core=" + coreFileName); + launcher.addToolArg("--exe=" + JDKToolFinder.getTestJDKTool("java")); + System.out.println("Starting clhsdb against corefile " + coreFileName + + " and exe " + JDKToolFinder.getTestJDKTool("java")); + + ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand()); + processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); + + toolProcess = processBuilder.start(); + } + + /** + * * Runs 'jhsdb clhsdb' commands and checks for expected and unexpected strings. * @param commands - clhsdb commands to execute. * @param expectedStrMap - Map of expected strings per command which need to @@ -159,4 +181,32 @@ attach(lingeredAppPid); return runCmd(commands, expectedStrMap, unExpectedStrMap); } + + /** + * + * Launches 'jhsdb clhsdb', loads a core file, executes the commands, + * checks for expected and unexpected strings. + * @param coreFileName - Name of the core file to be debugged. + * @param commands - clhsdb commands to execute. + * @param expectedStrMap - Map of expected strings per command which need to + * be checked in the output of the command. + * @param unExpectedStrMap - Map of unexpected strings per command which should + * not be present in the output of the command. + * @return Output of the commands as a String. + */ + public String runOnCore(String coreFileName, + List commands, + Map> expectedStrMap, + Map> unExpectedStrMap) + throws IOException, InterruptedException { + + if (!Platform.shouldSAAttach()) { + // Silently skip the test if we don't have enough permissions to attach + System.out.println("SA attach not expected to work - test skipped."); + return null; + } + + loadCore(coreFileName); + return runCmd(commands, expectedStrMap, unExpectedStrMap); + } } --- /dev/null 2018-04-24 16:10:17.224000000 +0530 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java 2018-04-25 08:29:44.401931000 +0530 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.memory; + +import java.util.*; +import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.runtime.VM; +import sun.jvm.hotspot.runtime.VMObject; +import sun.jvm.hotspot.runtime.VMObjectFactory; +import sun.jvm.hotspot.types.*; + +public class FileMapInfo { + private static FileMapHeader header; + private static Address headerValue; + + // Fields for class FileMapHeader + private static Address mdSpaceValue; + private static Address mdRegionBaseAddress; + private static Address mdRegionEndAddress; + + // HashMap created by mapping the vTable addresses in the md region with + // the corresponding metadata type. + private static Map vTableTypeMap; + + private static Type metadataTypeArray[]; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + // FileMapInfo + Type type = db.lookupType("FileMapInfo"); + AddressField currentInfoField = type.getAddressField("_current_info"); + long headerFieldOffset = type.getField("_header").getOffset(); + Address headerAddress = currentInfoField.getValue().addOffsetTo(headerFieldOffset); + headerValue = headerAddress.getAddressAt(0); + + // FileMapHeader + type = db.lookupType("FileMapInfo::FileMapHeader"); + AddressField spaceField = type.getAddressField("_space[0]"); + Address spaceValue = headerValue.addOffsetTo(type.getField("_space[0]").getOffset()); + mdSpaceValue = spaceValue.addOffsetTo(3 * spaceField.getSize()); + + // SpaceInfo + type = db.lookupType("FileMapInfo::FileMapHeader::space_info"); + long mdRegionBaseAddressOffset = type.getField("_addr._base").getOffset(); + mdRegionBaseAddress = (mdSpaceValue.addOffsetTo(mdRegionBaseAddressOffset)).getAddressAt(0); + long mdRegionSizeOffset = type.getField("_used").getOffset(); + long mdRegionSize = (mdSpaceValue.addOffsetTo(mdRegionSizeOffset)).getAddressAt(0).asLongValue(); + mdRegionEndAddress = mdRegionBaseAddress.addOffsetTo(mdRegionSize); + + populateMetadataTypeArray(db); + } + + private static void populateMetadataTypeArray(TypeDataBase db) { + metadataTypeArray = new Type[8]; + + metadataTypeArray[0] = db.lookupType("ConstantPool"); + metadataTypeArray[1] = db.lookupType("InstanceKlass"); + metadataTypeArray[2] = db.lookupType("InstanceClassLoaderKlass"); + metadataTypeArray[3] = db.lookupType("InstanceMirrorKlass"); + metadataTypeArray[4] = db.lookupType("InstanceRefKlass"); + metadataTypeArray[5] = db.lookupType("Method"); + metadataTypeArray[6] = db.lookupType("ObjArrayKlass"); + metadataTypeArray[7] = db.lookupType("TypeArrayKlass"); + } + + public FileMapHeader getHeader() { + if (header == null) { + header = (FileMapHeader) VMObjectFactory.newObject(FileMapInfo.FileMapHeader.class, headerValue); + } + return header; + } + + public boolean inCopiedVtableSpace(Address vptrAddress) { + FileMapHeader fmHeader = getHeader(); + return fmHeader.inCopiedVtableSpace(vptrAddress); + } + + public Type getTypeForVptrAddress(Address vptrAddress) { + if (vTableTypeMap == null) { + getHeader().createVtableTypeMapping(); + } + return vTableTypeMap.get(vptrAddress); + } + + + //------------------------------------------------------------------------------------------ + + public static class FileMapHeader extends VMObject { + + public FileMapHeader(Address addr) { + super(addr); + } + + public boolean inCopiedVtableSpace(Address vptrAddress) { + if (vptrAddress.greaterThan(mdRegionBaseAddress) && + vptrAddress.lessThanOrEqual(mdRegionEndAddress)) { + return true; + } + return false; + } + + public void createVtableTypeMapping() { + vTableTypeMap = new HashMap(); + long metadataVTableSize = 0; + long addressSize = VM.getVM().getAddressSize(); + + Address copiedVtableAddress = mdRegionBaseAddress; + for (int i=0; i < metadataTypeArray.length; i++) { + // The first entry denotes the vtable size. + metadataVTableSize = copiedVtableAddress.getAddressAt(0).asLongValue(); + vTableTypeMap.put(copiedVtableAddress.addOffsetTo(addressSize), metadataTypeArray[i]); + + // The '+ 1' below is to skip the entry containing the size of this metadata's vtable. + copiedVtableAddress = + copiedVtableAddress.addOffsetTo((metadataVTableSize + 1) * addressSize); + } + } + } +} --- /dev/null 2018-04-24 16:10:17.224000000 +0530 +++ new/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java 2018-04-25 08:29:45.021931000 +0530 @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8174994 + * @summary Test the clhsdb commands 'printmdo', 'printall' on a CDS enabled corefile. + * @requires vm.cds + * @requires os.family != "windows" + * @requires vm.flavor == "server" + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run main/othervm/timeout=2400 -Xmx1g ClhsdbCDSCore + */ + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import java.util.HashMap; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.CDSOptions; +import java.io.IOException; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import jdk.test.lib.Asserts; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import jdk.internal.misc.Unsafe; +import java.util.Scanner; + +class CrashApp { + public static void main(String[] args) { + Unsafe.getUnsafe().putInt(0L, 0); + } +} + +public class ClhsdbCDSCore { + + private static final String TEST_CDS_CORE_FILE_NAME = "cds_core_file"; + private static final String LOCATIONS_STRING = "location: "; + private static final String RUN_SHELL_NO_LIMIT = "ulimit -c unlimited && "; + private static final String SHARED_ARCHIVE_NAME = "ArchiveForClhsdbCDSCore.jsa"; + private static final String CORE_PATTERN_FILE_NAME = "/proc/sys/kernel/core_pattern"; + + public static void main(String[] args) throws Exception { + System.out.println("Starting ClhsdbCDSCore test"); + cleanup(); + + try { + CDSOptions opts = (new CDSOptions()).setArchiveName(SHARED_ARCHIVE_NAME); + CDSTestUtils.createArchiveAndCheck(opts); + + String[] jArgs = { + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + SHARED_ARCHIVE_NAME, + "-XX:+CreateCoredumpOnCrash", + "-Xshare:auto", + "-XX:+ProfileInterpreter", + "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + CrashApp.class.getName() + }; + + OutputAnalyzer crashOut; + try { + List options = new ArrayList<>(); + options.addAll(Arrays.asList(jArgs)); + crashOut = + ProcessTools.executeProcess(getTestJavaCommandlineWithPrefix( + RUN_SHELL_NO_LIMIT, options.toArray(new String[0]))); + } catch (Throwable t) { + throw new Error("Can't execute the java cds process.", t); + } + + System.out.println(crashOut.getOutput()); + String crashOutputString = crashOut.getOutput(); + String coreFileLocation = getCoreFileLocation(crashOutputString); + if (coreFileLocation == null) { + if (Platform.isOSX()) { + File coresDir = new File("/cores"); + if (!coresDir.isDirectory() || !coresDir.canWrite()) { + throw new Error("cores is not a directory or does not have write permissions"); + } + } else if (Platform.isLinux()) { + // Check if a crash report tool is installed. + File corePatternFile = new File(CORE_PATTERN_FILE_NAME); + Scanner scanner = new Scanner(corePatternFile); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + line = line.trim(); + System.out.println(line); + if (line.startsWith("|")) { + System.out.println( + "\nThis system uses a crash report tool ($cat /proc/sys/kernel/core_pattern).\n" + + "Core files might not be generated. Please reset /proc/sys/kernel/core_pattern\n" + + "to enable core generation. Skipping this test."); + cleanup(); + return; + } + } + } + throw new Error("Couldn't find core file location in: '" + crashOutputString + "'"); + } + try { + Asserts.assertGT(new File(coreFileLocation).length(), 0L, "Unexpected core size"); + Files.move(Paths.get(coreFileLocation), Paths.get(TEST_CDS_CORE_FILE_NAME)); + } catch (IOException ioe) { + throw new Error("Can't move core file: " + ioe, ioe); + } + + ClhsdbLauncher test = new ClhsdbLauncher(); + + // Ensure that UseSharedSpaces is turned on. + List cmds = List.of("flags UseSharedSpaces"); + + String useSharedSpacesOutput = test.runOnCore(TEST_CDS_CORE_FILE_NAME, cmds, + null, null); + + if (useSharedSpacesOutput == null) { + // Output could be null due to attach permission issues. + System.out.println("Could not determine the UseSharedSpaces value - test skipped."); + cleanup(); + return; + } + + if (!useSharedSpacesOutput.contains("true")) { + // CDS archive is not mapped. Skip the rest of the test. + System.out.println("The CDS archive is not mapped - test skipped."); + cleanup(); + return; + } + + cmds = List.of("printmdo -a", "printall"); + + Map> expStrMap = new HashMap<>(); + Map> unExpStrMap = new HashMap<>(); + expStrMap.put("printmdo -a", List.of( + "CounterData", + "BranchData")); + unExpStrMap.put("printmdo -a", List.of( + "No suitable match for type of address")); + expStrMap.put("printall", List.of( + "aload_0", + "Constant Pool of", + "public static void main(java.lang.String[])", + "Bytecode", + "invokevirtual", + "checkcast", + "Exception Table", + "invokedynamic")); + unExpStrMap.put("printall", List.of( + "sun.jvm.hotspot.types.WrongTypeException", + "No suitable match for type of address")); + test.runOnCore(TEST_CDS_CORE_FILE_NAME, cmds, expStrMap, unExpStrMap); + } catch (Exception ex) { + throw new RuntimeException("Test ERROR " + ex, ex); + } + cleanup(); + System.out.println("Test PASSED"); + } + + // lets search for a few possible locations using process output and return existing location + private static String getCoreFileLocation(String crashOutputString) { + Asserts.assertTrue(crashOutputString.contains(LOCATIONS_STRING), + "Output doesn't contain the location of core file."); + String stringWithLocation = Arrays.stream(crashOutputString.split("\\r?\\n")) + .filter(str -> str.contains(LOCATIONS_STRING)) + .findFirst() + .get(); + stringWithLocation = stringWithLocation.substring(stringWithLocation + .indexOf(LOCATIONS_STRING) + LOCATIONS_STRING.length()); + String coreWithPid; + if (stringWithLocation.contains("or ")) { + Matcher m = Pattern.compile("or.* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation); + if (!m.find()) { + throw new Error("Couldn't find path to core inside location string"); + } + coreWithPid = m.group(1); + } else { + coreWithPid = stringWithLocation.trim(); + } + if (new File(coreWithPid).exists()) { + return coreWithPid; + } + String justCore = Paths.get("core").toString(); + if (new File(justCore).exists()) { + return justCore; + } + Path coreWithPidPath = Paths.get(coreWithPid); + String justFile = coreWithPidPath.getFileName().toString(); + if (new File(justFile).exists()) { + return justFile; + } + Path parent = coreWithPidPath.getParent(); + if (parent != null) { + String coreWithoutPid = parent.resolve("core").toString(); + if (new File(coreWithoutPid).exists()) { + return coreWithoutPid; + } + } + return null; + } + + private static String[] getTestJavaCommandlineWithPrefix(String prefix, String... args) { + try { + String cmd = ProcessTools.getCommandLine(ProcessTools.createJavaProcessBuilder(true, args)); + return new String[]{"sh", "-c", prefix + cmd}; + } catch (Throwable t) { + throw new Error("Can't create process builder: " + t, t); + } + } + + private static void cleanup() { + remove(TEST_CDS_CORE_FILE_NAME); + remove(SHARED_ARCHIVE_NAME); + } + + private static void remove(String item) { + File toDelete = new File(item); + toDelete.delete(); + } +} --- /dev/null 2018-04-24 16:10:17.224000000 +0530 +++ new/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSJstackPrintAll.java 2018-04-25 08:29:45.633931000 +0530 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8174994 + * @summary Test the clhsdb commands 'jstack', 'printall' with CDS enabled + * @requires vm.cds + * @library /test/lib + * @run main/othervm/timeout=2400 -Xmx1g ClhsdbCDSJstackPrintAll + */ + +import java.util.List; +import java.util.Arrays; +import java.util.Map; +import java.util.HashMap; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.apps.LingeredApp; + +public class ClhsdbCDSJstackPrintAll { + + public static void main(String[] args) throws Exception { + System.out.println("Starting ClhsdbCDSJstackPrintAll test"); + String sharedArchiveName = "ArchiveForClhsdbJstackPrintAll.jsa"; + LingeredApp theApp = null; + + try { + CDSOptions opts = (new CDSOptions()).setArchiveName(sharedArchiveName); + CDSTestUtils.createArchiveAndCheck(opts); + + ClhsdbLauncher test = new ClhsdbLauncher(); + List vmArgs = Arrays.asList( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + sharedArchiveName, + "-Xshare:auto"); + theApp = LingeredApp.startApp(vmArgs); + System.out.println("Started LingeredApp with pid " + theApp.getPid()); + + // Ensure that UseSharedSpaces is turned on. + List cmds = List.of("flags UseSharedSpaces"); + + String useSharedSpacesOutput = test.run(theApp.getPid(), cmds, + null, null); + + if (useSharedSpacesOutput == null) { + // Attach permission issues. + System.out.println("Could not determine the UseSharedSpaces value - test skipped."); + LingeredApp.stopApp(theApp); + return; + } + + if (!useSharedSpacesOutput.contains("true")) { + // CDS archive is not mapped. Skip the rest of the test. + System.out.println("The CDS archive is not mapped - test skipped."); + LingeredApp.stopApp(theApp); + return; + } + + cmds = List.of("jstack -v", "printall"); + + Map> expStrMap = new HashMap<>(); + Map> unExpStrMap = new HashMap<>(); + expStrMap.put("jstack -v", List.of( + "No deadlocks found", + "Common-Cleaner", + "Signal Dispatcher", + "Method*", + "LingeredApp.main")); + unExpStrMap.put("jstack -v", List.of( + "sun.jvm.hotspot.types.WrongTypeException", + "No suitable match for type of address")); + expStrMap.put("printall", List.of( + "aload_0", + "Constant Pool of", + "public static void main(java.lang.String[])", + "Bytecode", + "invokevirtual", + "checkcast", + "Exception Table", + "invokedynamic")); + unExpStrMap.put("printall", List.of( + "No suitable match for type of address")); + test.run(theApp.getPid(), cmds, expStrMap, unExpStrMap); + } catch (Exception ex) { + throw new RuntimeException("Test ERROR " + ex, ex); + } finally { + LingeredApp.stopApp(theApp); + } + System.out.println("Test PASSED"); + } +}