8174994: SA: clhsdb printmdo throws WrongTypeException when attached to a process with CDS
Summary: Read in the md region of the CDS archive in SA and map the vtable addresses to the corresponding metadata type.
Reviewed-by: iklam, coleenp, ysuenaga, dholmes
--- a/src/hotspot/share/memory/filemap.hpp Wed Apr 25 22:12:06 2018 -0700
+++ b/src/hotspot/share/memory/filemap.hpp Thu Apr 26 12:25:36 2018 +0530
@@ -75,6 +75,7 @@
class FileMapInfo : public CHeapObj<mtInternal> {
private:
friend class ManifestStream;
+ friend class VMStructs;
enum {
_invalid_version = -1,
_current_version = 3
--- a/src/hotspot/share/runtime/vmStructs.cpp Wed Apr 25 22:12:06 2018 -0700
+++ b/src/hotspot/share/runtime/vmStructs.cpp Thu Apr 26 12:25:36 2018 +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"
@@ -1120,6 +1121,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 */ \
/******************/ \
@@ -1444,7 +1455,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 */ \
@@ -2000,6 +2011,10 @@
declare_toplevel_type(vframeArrayElement) \
declare_toplevel_type(Annotations*) \
declare_type(OopMapValue, StackObj) \
+ declare_type(FileMapInfo, CHeapObj<mtInternal>) \
+ declare_type(FileMapInfo::FileMapHeaderBase, CHeapObj<mtClass>) \
+ declare_type(FileMapInfo::FileMapHeader, FileMapInfo::FileMapHeaderBase)\
+ declare_toplevel_type(FileMapInfo::FileMapHeader::space_info) \
\
/************/ \
/* GC types */ \
--- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c Wed Apr 25 22:12:06 2018 -0700
+++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c Thu Apr 26 12:25:36 2018 +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
-
+ 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,
--- a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c Wed Apr 25 22:12:06 2018 -0700
+++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c Thu Apr 26 12:25:36 2018 +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
-
+ 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,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java Thu Apr 26 12:25:36 2018 +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<Address, Type> 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<Address, Type>();
+ 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);
+ }
+ }
+ }
+}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java Wed Apr 25 22:12:06 2018 -0700
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java Thu Apr 26 12:25:36 2018 +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());
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java Wed Apr 25 22:12:06 2018 -0700
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic/BasicTypeDataBase.java Thu Apr 26 12:25:36 2018 +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;
/** <P> 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();
--- a/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp Wed Apr 25 22:12:06 2018 -0700
+++ b/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp Thu Apr 26 12:25:36 2018 +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;
+
+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?
+ } _space[NUM_SHARED_MAPS];
- bool _read_only; // read only space?
- bool _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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSCore.java Thu Apr 26 12:25:36 2018 +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<String> 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<String> 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<String, List<String>> expStrMap = new HashMap<>();
+ Map<String, List<String>> 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 Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbCDSJstackPrintAll.java Thu Apr 26 12:25:36 2018 +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<String> 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<String> 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<String, List<String>> expStrMap = new HashMap<>();
+ Map<String, List<String>> 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");
+ }
+}
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbLauncher.java Wed Apr 25 22:12:06 2018 -0700
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbLauncher.java Thu Apr 26 12:25:36 2018 +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<String> commands,
+ Map<String, List<String>> expectedStrMap,
+ Map<String, List<String>> 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);
+ }
}